From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D2A7FC43441 for ; Tue, 13 Nov 2018 15:22:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9AEA82251C for ; Tue, 13 Nov 2018 15:22:41 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9AEA82251C Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388020AbeKNBVP (ORCPT ); Tue, 13 Nov 2018 20:21:15 -0500 Received: from mx1.redhat.com ([209.132.183.28]:41662 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732028AbeKNBVO (ORCPT ); Tue, 13 Nov 2018 20:21:14 -0500 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 4E1B93DDB8; Tue, 13 Nov 2018 15:22:39 +0000 (UTC) Received: from vitty.brq.redhat.com (unknown [10.34.244.70]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2094B1001938; Tue, 13 Nov 2018 15:22:36 +0000 (UTC) From: Vitaly Kuznetsov To: kvm@vger.kernel.org Cc: Paolo Bonzini , =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= , linux-kernel@vger.kernel.org, Roman Kagan , "K. Y. Srinivasan" , Haiyang Zhang , Stephen Hemminger , x86@kernel.org, "Michael Kelley (EOSG)" Subject: [kvm-unit-tests PATCH] x86/hyper-v: stimer_direct test Date: Tue, 13 Nov 2018 16:22:18 +0100 Message-Id: <20181113152218.22049-6-vkuznets@redhat.com> In-Reply-To: <20181113152218.22049-1-vkuznets@redhat.com> References: <20181113152218.22049-1-vkuznets@redhat.com> X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Tue, 13 Nov 2018 15:22:39 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Signed-off-by: Vitaly Kuznetsov --- x86/Makefile.common | 3 + x86/hyperv.h | 7 ++ x86/hyperv_stimer_direct.c | 250 +++++++++++++++++++++++++++++++++++++ x86/unittests.cfg | 6 + 4 files changed, 266 insertions(+) create mode 100644 x86/hyperv_stimer_direct.c diff --git a/x86/Makefile.common b/x86/Makefile.common index e612dbe..115189a 100644 --- a/x86/Makefile.common +++ b/x86/Makefile.common @@ -57,6 +57,7 @@ tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \ $(TEST_DIR)/tsc_adjust.flat $(TEST_DIR)/asyncpf.flat \ $(TEST_DIR)/init.flat $(TEST_DIR)/smap.flat \ $(TEST_DIR)/hyperv_synic.flat $(TEST_DIR)/hyperv_stimer.flat \ + $(TEST_DIR)/hyperv_stimer_direct.flat \ $(TEST_DIR)/hyperv_connections.flat \ $(TEST_DIR)/umip.flat @@ -81,6 +82,8 @@ $(TEST_DIR)/hyperv_synic.elf: $(TEST_DIR)/hyperv.o $(TEST_DIR)/hyperv_stimer.elf: $(TEST_DIR)/hyperv.o +$(TEST_DIR)/hyperv_stimer_direct.elf: $(TEST_DIR)/hyperv.o + $(TEST_DIR)/hyperv_connections.elf: $(TEST_DIR)/hyperv.o arch_clean: diff --git a/x86/hyperv.h b/x86/hyperv.h index 9a83da4..718744c 100644 --- a/x86/hyperv.h +++ b/x86/hyperv.h @@ -10,6 +10,8 @@ #define HV_X64_MSR_SYNIC_AVAILABLE (1 << 2) #define HV_X64_MSR_SYNTIMER_AVAILABLE (1 << 3) +#define HV_STIMER_DIRECT_MODE_AVAILABLE (1 << 19) + #define HV_X64_MSR_GUEST_OS_ID 0x40000000 #define HV_X64_MSR_HYPERCALL 0x40000001 @@ -205,6 +207,11 @@ static inline bool stimer_supported(void) return cpuid(HYPERV_CPUID_FEATURES).a & HV_X64_MSR_SYNIC_AVAILABLE; } +static inline bool stimer_direct_supported(void) +{ + return cpuid(HYPERV_CPUID_FEATURES).d & HV_STIMER_DIRECT_MODE_AVAILABLE; +} + static inline bool hv_time_ref_counter_supported(void) { return cpuid(HYPERV_CPUID_FEATURES).a & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE; diff --git a/x86/hyperv_stimer_direct.c b/x86/hyperv_stimer_direct.c new file mode 100644 index 0000000..e93f633 --- /dev/null +++ b/x86/hyperv_stimer_direct.c @@ -0,0 +1,250 @@ +#include "libcflat.h" +#include "processor.h" +#include "msr.h" +#include "isr.h" +#include "vm.h" +#include "apic.h" +#include "desc.h" +#include "smp.h" +#include "atomic.h" +#include "hyperv.h" +#include "asm/barrier.h" +#include "alloc_page.h" + +#define MAX_CPUS 4 + +#define INT1_VEC 0xF1 +#define INT2_VEC 0xF2 + +#define ONE_MS_IN_100NS 10000 + +struct stimer { + int sint; + int index; + atomic_t fire_count; +}; + +struct svcpu { + int vcpu; + struct stimer timer[HV_SYNIC_STIMER_COUNT]; +}; + +static struct svcpu g_synic_vcpu[MAX_CPUS]; + +static void stimer_init(struct stimer *timer, int index) +{ + memset(timer, 0, sizeof(*timer)); + timer->index = index; +} + +static void synic_enable(void) +{ + int vcpu = smp_id(), i; + struct svcpu *svcpu = &g_synic_vcpu[vcpu]; + + memset(svcpu, 0, sizeof(*svcpu)); + svcpu->vcpu = vcpu; + for (i = 0; i < ARRAY_SIZE(svcpu->timer); i++) { + stimer_init(&svcpu->timer[i], i); + } +} + +static void stimer_shutdown(struct stimer *timer) +{ + wrmsr(HV_X64_MSR_STIMER0_CONFIG + 2*timer->index, 0); +} + +static void process_stimer_expired(struct stimer *timer) +{ + atomic_inc(&timer->fire_count); +} + +static void __stimer_isr_direct(int vcpu, int timer_index) +{ + struct svcpu *svcpu = &g_synic_vcpu[vcpu]; + struct stimer *timer = &svcpu->timer[timer_index]; + + process_stimer_expired(timer); +} + +static void stimer_isr_direct1(isr_regs_t *regs) +{ + int vcpu = smp_id(); + + __stimer_isr_direct(vcpu, 0); + + eoi(); +} + +static void stimer_isr_direct2(isr_regs_t *regs) +{ + int vcpu = smp_id(); + + __stimer_isr_direct(vcpu, 1); + + eoi(); +} + +static void stimer_start(struct stimer *timer, + bool auto_enable, bool periodic, + u64 tick_100ns, int apic_vector) +{ + u64 count; + union hv_stimer_config config = {.as_uint64 = 0}; + + timer->sint = 0; + atomic_set(&timer->fire_count, 0); + + config.periodic = periodic; + config.enable = 1; + config.auto_enable = auto_enable; + config.direct_mode = 1; + config.sintx = 0; + config.apic_vector = apic_vector; + + if (periodic) { + count = tick_100ns; + } else { + count = rdmsr(HV_X64_MSR_TIME_REF_COUNT) + tick_100ns; + } + + if (!auto_enable) { + wrmsr(HV_X64_MSR_STIMER0_COUNT + timer->index*2, count); + wrmsr(HV_X64_MSR_STIMER0_CONFIG + timer->index*2, config.as_uint64); + } else { + wrmsr(HV_X64_MSR_STIMER0_CONFIG + timer->index*2, config.as_uint64); + wrmsr(HV_X64_MSR_STIMER0_COUNT + timer->index*2, count); + } +} + +static void stimers_shutdown(void) +{ + int vcpu = smp_id(), i; + struct svcpu *svcpu = &g_synic_vcpu[vcpu]; + + for (i = 0; i < ARRAY_SIZE(svcpu->timer); i++) { + stimer_shutdown(&svcpu->timer[i]); + } +} + +static void stimer_test_prepare(void *ctx) +{ + write_cr3((ulong)ctx); + synic_enable(); +} + +static void stimer_test_periodic(int vcpu, struct stimer *timer1, + struct stimer *timer2) +{ + /* Check periodic timers */ + stimer_start(timer1, false, true, ONE_MS_IN_100NS, INT1_VEC); + stimer_start(timer2, false, true, ONE_MS_IN_100NS, INT2_VEC); + while ((atomic_read(&timer1->fire_count) < 1000) || + (atomic_read(&timer2->fire_count) < 1000)) { + pause(); + } + report("Hyper-V SynIC periodic timers test vcpu %d", true, vcpu); + stimer_shutdown(timer1); + stimer_shutdown(timer2); +} + +static void stimer_test_one_shot(int vcpu, struct stimer *timer) +{ + /* Check one-shot timer */ + stimer_start(timer, false, false, ONE_MS_IN_100NS, INT1_VEC); + while (atomic_read(&timer->fire_count) < 1) { + pause(); + } + report("Hyper-V SynIC one-shot test vcpu %d", true, vcpu); + stimer_shutdown(timer); +} + +static void stimer_test_auto_enable_one_shot(int vcpu, struct stimer *timer) +{ + /* Check auto-enable one-shot timer */ + stimer_start(timer, true, false, ONE_MS_IN_100NS, INT2_VEC); + while (atomic_read(&timer->fire_count) < 1) { + pause(); + } + report("Hyper-V SynIC auto-enable one-shot timer test vcpu %d", true, vcpu); + stimer_shutdown(timer); +} + +static void stimer_test_auto_enable_periodic(int vcpu, struct stimer *timer) +{ + /* Check auto-enable periodic timer */ + stimer_start(timer, true, true, ONE_MS_IN_100NS, INT1_VEC); + while (atomic_read(&timer->fire_count) < 1000) { + pause(); + } + report("Hyper-V SynIC auto-enable periodic timer test vcpu %d", true, vcpu); + stimer_shutdown(timer); +} + +static void stimer_test(void *ctx) +{ + int vcpu = smp_id(); + struct svcpu *svcpu = &g_synic_vcpu[vcpu]; + struct stimer *timer1, *timer2; + + irq_enable(); + + timer1 = &svcpu->timer[0]; + timer2 = &svcpu->timer[1]; + + stimer_test_periodic(vcpu, timer1, timer2); + stimer_test_one_shot(vcpu, timer1); + stimer_test_auto_enable_one_shot(vcpu, timer2); + stimer_test_auto_enable_periodic(vcpu, timer1); + + irq_disable(); +} + +static void stimer_test_cleanup(void *ctx) +{ + stimers_shutdown(); +} + +static void stimer_test_all(void) +{ + int ncpus; + + setup_vm(); + smp_init(); + enable_apic(); + + ncpus = cpu_count(); + if (ncpus > MAX_CPUS) + report_abort("number cpus exceeds %d", MAX_CPUS); + printf("cpus = %d\n", ncpus); + + handle_irq(INT1_VEC, stimer_isr_direct1); + handle_irq(INT2_VEC, stimer_isr_direct2); + + on_cpus(stimer_test_prepare, (void *)read_cr3()); + on_cpus(stimer_test, NULL); + on_cpus(stimer_test_cleanup, NULL); +} + +int main(int ac, char **av) +{ + + if (!stimer_supported()) { + report("Hyper-V SynIC timers are not supported", true); + goto done; + } + + if (!hv_time_ref_counter_supported()) { + report("Hyper-V time reference counter is not supported", true); + goto done; + } + + if (!stimer_direct_supported()) { + report("Hyper-V direct mode for synthetic timers is not supported", true); + goto done; + } + + stimer_test_all(); +done: + return report_summary(); +} diff --git a/x86/unittests.cfg b/x86/unittests.cfg index c744a6d..36c0657 100644 --- a/x86/unittests.cfg +++ b/x86/unittests.cfg @@ -635,6 +635,12 @@ smp = 2 extra_params = -cpu kvm64,hv_vpindex,hv_time,hv_synic,hv_stimer -device hyperv-testdev groups = hyperv +[hyperv_stimer_direct] +file = hyperv_stimer_direct.flat +smp = 2 +extra_params = -cpu kvm64,hv_vpindex,hv_time,hv_synic,hv_stimer,hv_stimer_direct -device hyperv-testdev +groups = hyperv + [hyperv_clock] file = hyperv_clock.flat smp = 2 -- 2.17.2