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
synic_alloc_page(void)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
synic_free_page(void * page)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
stimer_init(struct stimer * timer,int index)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
synic_enable(void)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
stimer_shutdown(struct stimer * timer)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
process_stimer_expired(struct stimer * timer)89*367d44e2SVitaly Kuznetsov static void process_stimer_expired(struct stimer *timer)
9069d4bf75SAndrey Smetanin {
9169d4bf75SAndrey Smetanin atomic_inc(&timer->fire_count);
9269d4bf75SAndrey Smetanin }
9369d4bf75SAndrey Smetanin
process_stimer_msg(struct svcpu * svcpu,struct hv_message * msg,int sint)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
__stimer_isr(int vcpu)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
stimer_isr(isr_regs_t * regs)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
stimer_isr_auto_eoi(isr_regs_t * regs)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
__stimer_isr_direct(int vcpu,int timer_index)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
stimer_isr_direct1(isr_regs_t * regs)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
stimer_isr_direct2(isr_regs_t * regs)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
stimer_start(struct stimer * timer,bool auto_enable,bool periodic,u64 tick_100ns)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
stimers_shutdown(void)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
synic_disable(void)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
stimer_test_prepare(void * ctx)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
stimer_test_prepare_direct(void * ctx)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
stimer_test_periodic(int vcpu,struct stimer * timer1,struct stimer * timer2)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
stimer_test_one_shot(int vcpu,struct stimer * timer)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
stimer_test_auto_enable_one_shot(int vcpu,struct stimer * timer)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
stimer_test_auto_enable_periodic(int vcpu,struct stimer * timer)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
stimer_test_one_shot_busy(int vcpu,struct stimer * timer)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
stimer_test(void * ctx)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
stimer_test_cleanup(void * ctx)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
stimer_test_cleanup_direct(void * ctx)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
stimer_test_all(bool direct)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
main(int argc,char ** argv)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