169d4bf75SAndrey Smetanin #include "libcflat.h" 269d4bf75SAndrey Smetanin #include "processor.h" 369d4bf75SAndrey Smetanin #include "msr.h" 469d4bf75SAndrey Smetanin #include "isr.h" 569d4bf75SAndrey Smetanin #include "vm.h" 669d4bf75SAndrey Smetanin #include "apic.h" 769d4bf75SAndrey Smetanin #include "desc.h" 869d4bf75SAndrey Smetanin #include "smp.h" 969d4bf75SAndrey Smetanin #include "atomic.h" 1069d4bf75SAndrey Smetanin #include "hyperv.h" 118226c540SAlexander Gordeev #include "asm/barrier.h" 125aca024eSPaolo Bonzini #include "alloc_page.h" 1369d4bf75SAndrey Smetanin 1469d4bf75SAndrey Smetanin #define MAX_CPUS 4 1569d4bf75SAndrey Smetanin 1669d4bf75SAndrey Smetanin #define SINT1_VEC 0xF1 1769d4bf75SAndrey Smetanin #define SINT2_VEC 0xF2 1869d4bf75SAndrey Smetanin 19*367d44e2SVitaly Kuznetsov #define APIC_VEC1 0xF3 20*367d44e2SVitaly Kuznetsov #define APIC_VEC2 0xF4 21*367d44e2SVitaly Kuznetsov 2269d4bf75SAndrey Smetanin #define SINT1_NUM 2 2369d4bf75SAndrey Smetanin #define SINT2_NUM 3 2469d4bf75SAndrey Smetanin #define ONE_MS_IN_100NS 10000 2569d4bf75SAndrey Smetanin 2669d4bf75SAndrey Smetanin static struct spinlock g_synic_alloc_lock; 2769d4bf75SAndrey Smetanin 2869d4bf75SAndrey Smetanin struct stimer { 2969d4bf75SAndrey Smetanin int sint; 3069d4bf75SAndrey Smetanin int index; 31*367d44e2SVitaly Kuznetsov bool direct; 32*367d44e2SVitaly Kuznetsov int apic_vec; 3369d4bf75SAndrey Smetanin atomic_t fire_count; 3469d4bf75SAndrey Smetanin }; 3569d4bf75SAndrey Smetanin 3669d4bf75SAndrey Smetanin struct svcpu { 3769d4bf75SAndrey Smetanin int vcpu; 3869d4bf75SAndrey Smetanin void *msg_page; 3969d4bf75SAndrey Smetanin void *evt_page; 4069d4bf75SAndrey Smetanin struct stimer timer[HV_SYNIC_STIMER_COUNT]; 4169d4bf75SAndrey Smetanin }; 4269d4bf75SAndrey Smetanin 4369d4bf75SAndrey Smetanin static struct svcpu g_synic_vcpu[MAX_CPUS]; 4469d4bf75SAndrey Smetanin 4569d4bf75SAndrey Smetanin static void *synic_alloc_page(void) 4669d4bf75SAndrey Smetanin { 4769d4bf75SAndrey Smetanin void *page; 4869d4bf75SAndrey Smetanin 4969d4bf75SAndrey Smetanin spin_lock(&g_synic_alloc_lock); 5069d4bf75SAndrey Smetanin page = alloc_page(); 5169d4bf75SAndrey Smetanin spin_unlock(&g_synic_alloc_lock); 5269d4bf75SAndrey Smetanin return page; 5369d4bf75SAndrey Smetanin } 5469d4bf75SAndrey Smetanin 5569d4bf75SAndrey Smetanin static void synic_free_page(void *page) 5669d4bf75SAndrey Smetanin { 5769d4bf75SAndrey Smetanin spin_lock(&g_synic_alloc_lock); 5869d4bf75SAndrey Smetanin free_page(page); 5969d4bf75SAndrey Smetanin spin_unlock(&g_synic_alloc_lock); 6069d4bf75SAndrey Smetanin } 6169d4bf75SAndrey Smetanin 6269d4bf75SAndrey Smetanin static void stimer_init(struct stimer *timer, int index) 6369d4bf75SAndrey Smetanin { 6469d4bf75SAndrey Smetanin memset(timer, 0, sizeof(*timer)); 6569d4bf75SAndrey Smetanin timer->index = index; 6669d4bf75SAndrey Smetanin } 6769d4bf75SAndrey Smetanin 6869d4bf75SAndrey Smetanin static void synic_enable(void) 6969d4bf75SAndrey Smetanin { 7069d4bf75SAndrey Smetanin int vcpu = smp_id(), i; 7169d4bf75SAndrey Smetanin struct svcpu *svcpu = &g_synic_vcpu[vcpu]; 7269d4bf75SAndrey Smetanin 7369d4bf75SAndrey Smetanin memset(svcpu, 0, sizeof(*svcpu)); 7469d4bf75SAndrey Smetanin svcpu->vcpu = vcpu; 7569d4bf75SAndrey Smetanin svcpu->msg_page = synic_alloc_page(); 7669d4bf75SAndrey Smetanin for (i = 0; i < ARRAY_SIZE(svcpu->timer); i++) { 7769d4bf75SAndrey Smetanin stimer_init(&svcpu->timer[i], i); 7869d4bf75SAndrey Smetanin } 7969d4bf75SAndrey Smetanin wrmsr(HV_X64_MSR_SIMP, (u64)virt_to_phys(svcpu->msg_page) | 8069d4bf75SAndrey Smetanin HV_SYNIC_SIMP_ENABLE); 8169d4bf75SAndrey Smetanin wrmsr(HV_X64_MSR_SCONTROL, HV_SYNIC_CONTROL_ENABLE); 8269d4bf75SAndrey Smetanin } 8369d4bf75SAndrey Smetanin 8469d4bf75SAndrey Smetanin static void stimer_shutdown(struct stimer *timer) 8569d4bf75SAndrey Smetanin { 8669d4bf75SAndrey Smetanin wrmsr(HV_X64_MSR_STIMER0_CONFIG + 2*timer->index, 0); 8769d4bf75SAndrey Smetanin } 8869d4bf75SAndrey Smetanin 89*367d44e2SVitaly Kuznetsov static void process_stimer_expired(struct stimer *timer) 9069d4bf75SAndrey Smetanin { 9169d4bf75SAndrey Smetanin atomic_inc(&timer->fire_count); 9269d4bf75SAndrey Smetanin } 9369d4bf75SAndrey Smetanin 9469d4bf75SAndrey Smetanin static void process_stimer_msg(struct svcpu *svcpu, 9569d4bf75SAndrey Smetanin struct hv_message *msg, int sint) 9669d4bf75SAndrey Smetanin { 9769d4bf75SAndrey Smetanin struct hv_timer_message_payload *payload = 9869d4bf75SAndrey Smetanin (struct hv_timer_message_payload *)msg->u.payload; 9969d4bf75SAndrey Smetanin struct stimer *timer; 10069d4bf75SAndrey Smetanin 10169d4bf75SAndrey Smetanin if (msg->header.message_type != HVMSG_TIMER_EXPIRED && 10269d4bf75SAndrey Smetanin msg->header.message_type != HVMSG_NONE) { 103198dfd0eSJanis Schoetterl-Glausch report_fail("invalid Hyper-V SynIC msg type"); 10469d4bf75SAndrey Smetanin report_summary(); 105a2b7c499SAndrew Jones abort(); 10669d4bf75SAndrey Smetanin } 10769d4bf75SAndrey Smetanin 10869d4bf75SAndrey Smetanin if (msg->header.message_type == HVMSG_NONE) { 10969d4bf75SAndrey Smetanin return; 11069d4bf75SAndrey Smetanin } 11169d4bf75SAndrey Smetanin 11269d4bf75SAndrey Smetanin if (msg->header.payload_size < sizeof(*payload)) { 113198dfd0eSJanis Schoetterl-Glausch report_fail("invalid Hyper-V SynIC msg payload size"); 11469d4bf75SAndrey Smetanin report_summary(); 115a2b7c499SAndrew Jones abort(); 11669d4bf75SAndrey Smetanin } 11769d4bf75SAndrey Smetanin 11869d4bf75SAndrey Smetanin /* Now process timer expiration message */ 11969d4bf75SAndrey Smetanin 12069d4bf75SAndrey Smetanin if (payload->timer_index >= ARRAY_SIZE(svcpu->timer)) { 121198dfd0eSJanis Schoetterl-Glausch report_fail("invalid Hyper-V SynIC timer index"); 12269d4bf75SAndrey Smetanin report_summary(); 123a2b7c499SAndrew Jones abort(); 12469d4bf75SAndrey Smetanin } 12569d4bf75SAndrey Smetanin timer = &svcpu->timer[payload->timer_index]; 126*367d44e2SVitaly Kuznetsov 127*367d44e2SVitaly Kuznetsov if (timer->direct) { 128*367d44e2SVitaly Kuznetsov report(false, "VMBus message in direct mode received"); 129*367d44e2SVitaly Kuznetsov report_summary(); 130*367d44e2SVitaly Kuznetsov abort(); 131*367d44e2SVitaly Kuznetsov } 132*367d44e2SVitaly Kuznetsov 133*367d44e2SVitaly Kuznetsov process_stimer_expired(timer); 13469d4bf75SAndrey Smetanin 13569d4bf75SAndrey Smetanin msg->header.message_type = HVMSG_NONE; 13669d4bf75SAndrey Smetanin mb(); 13769d4bf75SAndrey Smetanin if (msg->header.message_flags.msg_pending) { 13869d4bf75SAndrey Smetanin wrmsr(HV_X64_MSR_EOM, 0); 13969d4bf75SAndrey Smetanin } 14069d4bf75SAndrey Smetanin } 14169d4bf75SAndrey Smetanin 14269d4bf75SAndrey Smetanin static void __stimer_isr(int vcpu) 14369d4bf75SAndrey Smetanin { 14469d4bf75SAndrey Smetanin struct svcpu *svcpu = &g_synic_vcpu[vcpu]; 14569d4bf75SAndrey Smetanin struct hv_message_page *msg_page; 14669d4bf75SAndrey Smetanin struct hv_message *msg; 14769d4bf75SAndrey Smetanin int i; 14869d4bf75SAndrey Smetanin 14969d4bf75SAndrey Smetanin 15069d4bf75SAndrey Smetanin msg_page = (struct hv_message_page *)svcpu->msg_page; 15169d4bf75SAndrey Smetanin for (i = 0; i < ARRAY_SIZE(msg_page->sint_message); i++) { 15269d4bf75SAndrey Smetanin msg = &msg_page->sint_message[i]; 15369d4bf75SAndrey Smetanin process_stimer_msg(svcpu, msg, i); 15469d4bf75SAndrey Smetanin } 15569d4bf75SAndrey Smetanin } 15669d4bf75SAndrey Smetanin 15769d4bf75SAndrey Smetanin static void stimer_isr(isr_regs_t *regs) 15869d4bf75SAndrey Smetanin { 15969d4bf75SAndrey Smetanin int vcpu = smp_id(); 16069d4bf75SAndrey Smetanin 16169d4bf75SAndrey Smetanin __stimer_isr(vcpu); 16269d4bf75SAndrey Smetanin eoi(); 16369d4bf75SAndrey Smetanin } 16469d4bf75SAndrey Smetanin 16569d4bf75SAndrey Smetanin static void stimer_isr_auto_eoi(isr_regs_t *regs) 16669d4bf75SAndrey Smetanin { 16769d4bf75SAndrey Smetanin int vcpu = smp_id(); 16869d4bf75SAndrey Smetanin 16969d4bf75SAndrey Smetanin __stimer_isr(vcpu); 17069d4bf75SAndrey Smetanin } 17169d4bf75SAndrey Smetanin 172*367d44e2SVitaly Kuznetsov static void __stimer_isr_direct(int vcpu, int timer_index) 173*367d44e2SVitaly Kuznetsov { 174*367d44e2SVitaly Kuznetsov struct svcpu *svcpu = &g_synic_vcpu[vcpu]; 175*367d44e2SVitaly Kuznetsov struct stimer *timer = &svcpu->timer[timer_index]; 176*367d44e2SVitaly Kuznetsov 177*367d44e2SVitaly Kuznetsov process_stimer_expired(timer); 178*367d44e2SVitaly Kuznetsov } 179*367d44e2SVitaly Kuznetsov 180*367d44e2SVitaly Kuznetsov static void stimer_isr_direct1(isr_regs_t *regs) 181*367d44e2SVitaly Kuznetsov { 182*367d44e2SVitaly Kuznetsov int vcpu = smp_id(); 183*367d44e2SVitaly Kuznetsov 184*367d44e2SVitaly Kuznetsov __stimer_isr_direct(vcpu, 0); 185*367d44e2SVitaly Kuznetsov 186*367d44e2SVitaly Kuznetsov eoi(); 187*367d44e2SVitaly Kuznetsov } 188*367d44e2SVitaly Kuznetsov 189*367d44e2SVitaly Kuznetsov static void stimer_isr_direct2(isr_regs_t *regs) 190*367d44e2SVitaly Kuznetsov { 191*367d44e2SVitaly Kuznetsov int vcpu = smp_id(); 192*367d44e2SVitaly Kuznetsov 193*367d44e2SVitaly Kuznetsov __stimer_isr_direct(vcpu, 1); 194*367d44e2SVitaly Kuznetsov 195*367d44e2SVitaly Kuznetsov eoi(); 196*367d44e2SVitaly Kuznetsov } 197*367d44e2SVitaly Kuznetsov 19869d4bf75SAndrey Smetanin static void stimer_start(struct stimer *timer, 19969d4bf75SAndrey Smetanin bool auto_enable, bool periodic, 200fd6b4b77SVitaly Kuznetsov u64 tick_100ns) 20169d4bf75SAndrey Smetanin { 20230353da7SVitaly Kuznetsov u64 count; 20330353da7SVitaly Kuznetsov union hv_stimer_config config = {.as_uint64 = 0}; 20469d4bf75SAndrey Smetanin 20569d4bf75SAndrey Smetanin atomic_set(&timer->fire_count, 0); 20669d4bf75SAndrey Smetanin 20730353da7SVitaly Kuznetsov config.periodic = periodic; 20830353da7SVitaly Kuznetsov config.enable = 1; 20930353da7SVitaly Kuznetsov config.auto_enable = auto_enable; 210*367d44e2SVitaly Kuznetsov if (!timer->direct) { 21130353da7SVitaly Kuznetsov config.sintx = timer->sint; 212*367d44e2SVitaly Kuznetsov } else { 213*367d44e2SVitaly Kuznetsov config.direct_mode = 1; 214*367d44e2SVitaly Kuznetsov config.apic_vector = timer->apic_vec; 215*367d44e2SVitaly Kuznetsov } 21669d4bf75SAndrey Smetanin 21769d4bf75SAndrey Smetanin if (periodic) { 21869d4bf75SAndrey Smetanin count = tick_100ns; 21969d4bf75SAndrey Smetanin } else { 22069d4bf75SAndrey Smetanin count = rdmsr(HV_X64_MSR_TIME_REF_COUNT) + tick_100ns; 22169d4bf75SAndrey Smetanin } 22269d4bf75SAndrey Smetanin 22369d4bf75SAndrey Smetanin if (!auto_enable) { 22469d4bf75SAndrey Smetanin wrmsr(HV_X64_MSR_STIMER0_COUNT + timer->index*2, count); 22530353da7SVitaly Kuznetsov wrmsr(HV_X64_MSR_STIMER0_CONFIG + timer->index*2, config.as_uint64); 22669d4bf75SAndrey Smetanin } else { 22730353da7SVitaly Kuznetsov wrmsr(HV_X64_MSR_STIMER0_CONFIG + timer->index*2, config.as_uint64); 22869d4bf75SAndrey Smetanin wrmsr(HV_X64_MSR_STIMER0_COUNT + timer->index*2, count); 22969d4bf75SAndrey Smetanin } 23069d4bf75SAndrey Smetanin } 23169d4bf75SAndrey Smetanin 23269d4bf75SAndrey Smetanin static void stimers_shutdown(void) 23369d4bf75SAndrey Smetanin { 23469d4bf75SAndrey Smetanin int vcpu = smp_id(), i; 23569d4bf75SAndrey Smetanin struct svcpu *svcpu = &g_synic_vcpu[vcpu]; 23669d4bf75SAndrey Smetanin 23769d4bf75SAndrey Smetanin for (i = 0; i < ARRAY_SIZE(svcpu->timer); i++) { 23869d4bf75SAndrey Smetanin stimer_shutdown(&svcpu->timer[i]); 23969d4bf75SAndrey Smetanin } 24069d4bf75SAndrey Smetanin } 24169d4bf75SAndrey Smetanin 24269d4bf75SAndrey Smetanin static void synic_disable(void) 24369d4bf75SAndrey Smetanin { 24469d4bf75SAndrey Smetanin int vcpu = smp_id(); 24569d4bf75SAndrey Smetanin struct svcpu *svcpu = &g_synic_vcpu[vcpu]; 24669d4bf75SAndrey Smetanin 24769d4bf75SAndrey Smetanin wrmsr(HV_X64_MSR_SCONTROL, 0); 24869d4bf75SAndrey Smetanin wrmsr(HV_X64_MSR_SIMP, 0); 24969d4bf75SAndrey Smetanin wrmsr(HV_X64_MSR_SIEFP, 0); 25069d4bf75SAndrey Smetanin synic_free_page(svcpu->msg_page); 25169d4bf75SAndrey Smetanin } 25269d4bf75SAndrey Smetanin 25369d4bf75SAndrey Smetanin 25469d4bf75SAndrey Smetanin static void stimer_test_prepare(void *ctx) 25569d4bf75SAndrey Smetanin { 256fd6b4b77SVitaly Kuznetsov int vcpu = smp_id(); 257fd6b4b77SVitaly Kuznetsov struct svcpu *svcpu = &g_synic_vcpu[vcpu]; 258fd6b4b77SVitaly Kuznetsov struct stimer *timer1, *timer2; 259fd6b4b77SVitaly Kuznetsov 26069d4bf75SAndrey Smetanin write_cr3((ulong)ctx); 26169d4bf75SAndrey Smetanin synic_enable(); 262fd6b4b77SVitaly Kuznetsov 263d2c248afSRoman Kagan synic_sint_create(SINT1_NUM, SINT1_VEC, false); 264d2c248afSRoman Kagan synic_sint_create(SINT2_NUM, SINT2_VEC, true); 265fd6b4b77SVitaly Kuznetsov 266fd6b4b77SVitaly Kuznetsov timer1 = &svcpu->timer[0]; 267fd6b4b77SVitaly Kuznetsov timer2 = &svcpu->timer[1]; 268fd6b4b77SVitaly Kuznetsov 269fd6b4b77SVitaly Kuznetsov timer1->sint = SINT1_NUM; 270fd6b4b77SVitaly Kuznetsov timer2->sint = SINT2_NUM; 27169d4bf75SAndrey Smetanin } 27269d4bf75SAndrey Smetanin 273*367d44e2SVitaly Kuznetsov static void stimer_test_prepare_direct(void *ctx) 274*367d44e2SVitaly Kuznetsov { 275*367d44e2SVitaly Kuznetsov int vcpu = smp_id(); 276*367d44e2SVitaly Kuznetsov struct svcpu *svcpu = &g_synic_vcpu[vcpu]; 277*367d44e2SVitaly Kuznetsov struct stimer *timer1, *timer2; 278*367d44e2SVitaly Kuznetsov 279*367d44e2SVitaly Kuznetsov write_cr3((ulong)ctx); 280*367d44e2SVitaly Kuznetsov 281*367d44e2SVitaly Kuznetsov timer1 = &svcpu->timer[0]; 282*367d44e2SVitaly Kuznetsov timer2 = &svcpu->timer[1]; 283*367d44e2SVitaly Kuznetsov 284*367d44e2SVitaly Kuznetsov stimer_init(timer1, 0); 285*367d44e2SVitaly Kuznetsov stimer_init(timer2, 1); 286*367d44e2SVitaly Kuznetsov 287*367d44e2SVitaly Kuznetsov timer1->apic_vec = APIC_VEC1; 288*367d44e2SVitaly Kuznetsov timer2->apic_vec = APIC_VEC2; 289*367d44e2SVitaly Kuznetsov 290*367d44e2SVitaly Kuznetsov timer1->direct = true; 291*367d44e2SVitaly Kuznetsov timer2->direct = true; 292*367d44e2SVitaly Kuznetsov } 293*367d44e2SVitaly Kuznetsov 294*367d44e2SVitaly Kuznetsov 29569d4bf75SAndrey Smetanin static void stimer_test_periodic(int vcpu, struct stimer *timer1, 29669d4bf75SAndrey Smetanin struct stimer *timer2) 29769d4bf75SAndrey Smetanin { 29869d4bf75SAndrey Smetanin /* Check periodic timers */ 299fd6b4b77SVitaly Kuznetsov stimer_start(timer1, false, true, ONE_MS_IN_100NS); 300fd6b4b77SVitaly Kuznetsov stimer_start(timer2, false, true, ONE_MS_IN_100NS); 30169d4bf75SAndrey Smetanin while ((atomic_read(&timer1->fire_count) < 1000) || 30269d4bf75SAndrey Smetanin (atomic_read(&timer2->fire_count) < 1000)) { 30369d4bf75SAndrey Smetanin pause(); 30469d4bf75SAndrey Smetanin } 3055c3582f0SJanis Schoetterl-Glausch report_pass("Hyper-V SynIC periodic timers test vcpu %d", vcpu); 30669d4bf75SAndrey Smetanin stimer_shutdown(timer1); 30769d4bf75SAndrey Smetanin stimer_shutdown(timer2); 30869d4bf75SAndrey Smetanin } 30969d4bf75SAndrey Smetanin 31069d4bf75SAndrey Smetanin static void stimer_test_one_shot(int vcpu, struct stimer *timer) 31169d4bf75SAndrey Smetanin { 31269d4bf75SAndrey Smetanin /* Check one-shot timer */ 313fd6b4b77SVitaly Kuznetsov stimer_start(timer, false, false, ONE_MS_IN_100NS); 31469d4bf75SAndrey Smetanin while (atomic_read(&timer->fire_count) < 1) { 31569d4bf75SAndrey Smetanin pause(); 31669d4bf75SAndrey Smetanin } 3175c3582f0SJanis Schoetterl-Glausch report_pass("Hyper-V SynIC one-shot test vcpu %d", vcpu); 31869d4bf75SAndrey Smetanin stimer_shutdown(timer); 31969d4bf75SAndrey Smetanin } 32069d4bf75SAndrey Smetanin 32169d4bf75SAndrey Smetanin static void stimer_test_auto_enable_one_shot(int vcpu, struct stimer *timer) 32269d4bf75SAndrey Smetanin { 32369d4bf75SAndrey Smetanin /* Check auto-enable one-shot timer */ 324fd6b4b77SVitaly Kuznetsov stimer_start(timer, true, false, ONE_MS_IN_100NS); 32569d4bf75SAndrey Smetanin while (atomic_read(&timer->fire_count) < 1) { 32669d4bf75SAndrey Smetanin pause(); 32769d4bf75SAndrey Smetanin } 3285c3582f0SJanis Schoetterl-Glausch report_pass("Hyper-V SynIC auto-enable one-shot timer test vcpu %d", vcpu); 32969d4bf75SAndrey Smetanin stimer_shutdown(timer); 33069d4bf75SAndrey Smetanin } 33169d4bf75SAndrey Smetanin 33269d4bf75SAndrey Smetanin static void stimer_test_auto_enable_periodic(int vcpu, struct stimer *timer) 33369d4bf75SAndrey Smetanin { 33469d4bf75SAndrey Smetanin /* Check auto-enable periodic timer */ 335fd6b4b77SVitaly Kuznetsov stimer_start(timer, true, true, ONE_MS_IN_100NS); 33669d4bf75SAndrey Smetanin while (atomic_read(&timer->fire_count) < 1000) { 33769d4bf75SAndrey Smetanin pause(); 33869d4bf75SAndrey Smetanin } 3395c3582f0SJanis Schoetterl-Glausch report_pass("Hyper-V SynIC auto-enable periodic timer test vcpu %d", vcpu); 34069d4bf75SAndrey Smetanin stimer_shutdown(timer); 34169d4bf75SAndrey Smetanin } 34269d4bf75SAndrey Smetanin 343cf12f77aSRoman Kagan static void stimer_test_one_shot_busy(int vcpu, struct stimer *timer) 344cf12f77aSRoman Kagan { 345*367d44e2SVitaly Kuznetsov struct hv_message_page *msg_page; 346*367d44e2SVitaly Kuznetsov struct hv_message *msg; 347*367d44e2SVitaly Kuznetsov 348*367d44e2SVitaly Kuznetsov /* Skipping msg slot busy test in direct mode */ 349*367d44e2SVitaly Kuznetsov if (timer->direct) 350*367d44e2SVitaly Kuznetsov return; 351*367d44e2SVitaly Kuznetsov 352*367d44e2SVitaly Kuznetsov msg_page = g_synic_vcpu[vcpu].msg_page; 353*367d44e2SVitaly Kuznetsov msg = &msg_page->sint_message[timer->sint]; 354cf12f77aSRoman Kagan 355cf12f77aSRoman Kagan msg->header.message_type = HVMSG_TIMER_EXPIRED; 356cf12f77aSRoman Kagan wmb(); 357cf12f77aSRoman Kagan 358fd6b4b77SVitaly Kuznetsov stimer_start(timer, false, false, ONE_MS_IN_100NS); 359cf12f77aSRoman Kagan 360cf12f77aSRoman Kagan do 361cf12f77aSRoman Kagan rmb(); 362cf12f77aSRoman Kagan while (!msg->header.message_flags.msg_pending); 363cf12f77aSRoman Kagan 364a299895bSThomas Huth report(!atomic_read(&timer->fire_count), 365a299895bSThomas Huth "no timer fired while msg slot busy: vcpu %d", vcpu); 366cf12f77aSRoman Kagan 367cf12f77aSRoman Kagan msg->header.message_type = HVMSG_NONE; 368cf12f77aSRoman Kagan wmb(); 369cf12f77aSRoman Kagan wrmsr(HV_X64_MSR_EOM, 0); 370cf12f77aSRoman Kagan 371cf12f77aSRoman Kagan while (atomic_read(&timer->fire_count) < 1) { 372cf12f77aSRoman Kagan pause(); 373cf12f77aSRoman Kagan } 3745c3582f0SJanis Schoetterl-Glausch report_pass("timer resumed when msg slot released: vcpu %d", vcpu); 375cf12f77aSRoman Kagan 376cf12f77aSRoman Kagan stimer_shutdown(timer); 377cf12f77aSRoman Kagan } 378cf12f77aSRoman Kagan 37969d4bf75SAndrey Smetanin static void stimer_test(void *ctx) 38069d4bf75SAndrey Smetanin { 38169d4bf75SAndrey Smetanin int vcpu = smp_id(); 38269d4bf75SAndrey Smetanin struct svcpu *svcpu = &g_synic_vcpu[vcpu]; 38369d4bf75SAndrey Smetanin struct stimer *timer1, *timer2; 38469d4bf75SAndrey Smetanin 385787f0aebSMaxim Levitsky sti(); 38669d4bf75SAndrey Smetanin 38769d4bf75SAndrey Smetanin timer1 = &svcpu->timer[0]; 38869d4bf75SAndrey Smetanin timer2 = &svcpu->timer[1]; 38969d4bf75SAndrey Smetanin 39069d4bf75SAndrey Smetanin stimer_test_periodic(vcpu, timer1, timer2); 39169d4bf75SAndrey Smetanin stimer_test_one_shot(vcpu, timer1); 39269d4bf75SAndrey Smetanin stimer_test_auto_enable_one_shot(vcpu, timer2); 39369d4bf75SAndrey Smetanin stimer_test_auto_enable_periodic(vcpu, timer1); 394cf12f77aSRoman Kagan stimer_test_one_shot_busy(vcpu, timer1); 39569d4bf75SAndrey Smetanin 396787f0aebSMaxim Levitsky cli(); 39769d4bf75SAndrey Smetanin } 39869d4bf75SAndrey Smetanin 39969d4bf75SAndrey Smetanin static void stimer_test_cleanup(void *ctx) 40069d4bf75SAndrey Smetanin { 40169d4bf75SAndrey Smetanin stimers_shutdown(); 402d2c248afSRoman Kagan synic_sint_destroy(SINT1_NUM); 403d2c248afSRoman Kagan synic_sint_destroy(SINT2_NUM); 40469d4bf75SAndrey Smetanin synic_disable(); 40569d4bf75SAndrey Smetanin } 40669d4bf75SAndrey Smetanin 407*367d44e2SVitaly Kuznetsov static void stimer_test_cleanup_direct(void *ctx) 408*367d44e2SVitaly Kuznetsov { 409*367d44e2SVitaly Kuznetsov stimers_shutdown(); 410*367d44e2SVitaly Kuznetsov } 411*367d44e2SVitaly Kuznetsov 412*367d44e2SVitaly Kuznetsov static void stimer_test_all(bool direct) 41369d4bf75SAndrey Smetanin { 41469d4bf75SAndrey Smetanin int ncpus; 41569d4bf75SAndrey Smetanin 41669d4bf75SAndrey Smetanin setup_vm(); 41769d4bf75SAndrey Smetanin enable_apic(); 41869d4bf75SAndrey Smetanin 4199b910f27SAndrew Jones ncpus = cpu_count(); 4209b910f27SAndrew Jones if (ncpus > MAX_CPUS) 4219b910f27SAndrew Jones report_abort("number cpus exceeds %d", MAX_CPUS); 4229b910f27SAndrew Jones printf("cpus = %d\n", ncpus); 4239b910f27SAndrew Jones 424*367d44e2SVitaly Kuznetsov if (!direct) { 425*367d44e2SVitaly Kuznetsov printf("Starting Hyper-V SynIC timers tests: message mode\n"); 426*367d44e2SVitaly Kuznetsov 42769d4bf75SAndrey Smetanin handle_irq(SINT1_VEC, stimer_isr); 42869d4bf75SAndrey Smetanin handle_irq(SINT2_VEC, stimer_isr_auto_eoi); 42969d4bf75SAndrey Smetanin 4309b910f27SAndrew Jones on_cpus(stimer_test_prepare, (void *)read_cr3()); 4319b910f27SAndrew Jones on_cpus(stimer_test, NULL); 4329b910f27SAndrew Jones on_cpus(stimer_test_cleanup, NULL); 433*367d44e2SVitaly Kuznetsov } else { 434*367d44e2SVitaly Kuznetsov printf("Starting Hyper-V SynIC timers tests: direct mode\n"); 435*367d44e2SVitaly Kuznetsov 436*367d44e2SVitaly Kuznetsov handle_irq(APIC_VEC1, stimer_isr_direct1); 437*367d44e2SVitaly Kuznetsov handle_irq(APIC_VEC2, stimer_isr_direct2); 438*367d44e2SVitaly Kuznetsov 439*367d44e2SVitaly Kuznetsov on_cpus(stimer_test_prepare_direct, (void *)read_cr3()); 440*367d44e2SVitaly Kuznetsov on_cpus(stimer_test, NULL); 441*367d44e2SVitaly Kuznetsov on_cpus(stimer_test_cleanup_direct, NULL); 442*367d44e2SVitaly Kuznetsov } 44369d4bf75SAndrey Smetanin } 44469d4bf75SAndrey Smetanin 445*367d44e2SVitaly Kuznetsov int main(int argc, char **argv) 44669d4bf75SAndrey Smetanin { 447*367d44e2SVitaly Kuznetsov bool direct = argc >= 2 && !strcmp(argv[1], "direct"); 44869d4bf75SAndrey Smetanin 449e53b4aceSMetin Kaya if (!hv_synic_supported()) { 45011769d1bSVitaly Kuznetsov report_skip("Hyper-V SynIC is not supported"); 45169d4bf75SAndrey Smetanin goto done; 45269d4bf75SAndrey Smetanin } 45369d4bf75SAndrey Smetanin 454e53b4aceSMetin Kaya if (!hv_stimer_supported()) { 45511769d1bSVitaly Kuznetsov report_skip("Hyper-V SynIC timers are not supported"); 45669d4bf75SAndrey Smetanin goto done; 45769d4bf75SAndrey Smetanin } 45869d4bf75SAndrey Smetanin 45969d4bf75SAndrey Smetanin if (!hv_time_ref_counter_supported()) { 46011769d1bSVitaly Kuznetsov report_skip("Hyper-V time reference counter is not supported"); 46169d4bf75SAndrey Smetanin goto done; 46269d4bf75SAndrey Smetanin } 46369d4bf75SAndrey Smetanin 464*367d44e2SVitaly Kuznetsov if (direct && !stimer_direct_supported()) { 465*367d44e2SVitaly Kuznetsov report_skip("Hyper-V SinIC timer direct mode is not supported"); 466*367d44e2SVitaly Kuznetsov } 467*367d44e2SVitaly Kuznetsov 468*367d44e2SVitaly Kuznetsov stimer_test_all(direct); 46969d4bf75SAndrey Smetanin done: 47069d4bf75SAndrey Smetanin return report_summary(); 47169d4bf75SAndrey Smetanin } 472