Skip to content

Commit e096fe2

Browse files
romank-msftliuw
authored andcommitted
Drivers: hv: Functions for setting up and tearing down the paravisor SynIC
The confidential VMBus runs with the paravisor SynIC and requires configuring it with the paravisor. Add the functions for configuring the paravisor SynIC. Update overall SynIC initialization logic to initialize the SynIC if it is present. Finally, break out SynIC interrupt enable/disable code into separate functions so that SynIC interrupts can be enabled or disabled via the paravisor instead of the hypervisor if the paravisor SynIC is present. Signed-off-by: Roman Kisel <romank@linux.microsoft.com> Reviewed-by: Michael Kelley <mhklinux@outlook.com> Signed-off-by: Wei Liu <wei.liu@kernel.org>
1 parent 74fa5d7 commit e096fe2

1 file changed

Lines changed: 126 additions & 12 deletions

File tree

drivers/hv/hv.c

Lines changed: 126 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -278,9 +278,8 @@ void hv_hyp_synic_enable_regs(unsigned int cpu)
278278
union hv_synic_simp simp;
279279
union hv_synic_siefp siefp;
280280
union hv_synic_sint shared_sint;
281-
union hv_synic_scontrol sctrl;
282281

283-
/* Setup the Synic's message page */
282+
/* Setup the Synic's message page with the hypervisor. */
284283
simp.as_uint64 = hv_get_msr(HV_MSR_SIMP);
285284
simp.simp_enabled = 1;
286285

@@ -299,7 +298,7 @@ void hv_hyp_synic_enable_regs(unsigned int cpu)
299298

300299
hv_set_msr(HV_MSR_SIMP, simp.as_uint64);
301300

302-
/* Setup the Synic's event page */
301+
/* Setup the Synic's event page with the hypervisor. */
303302
siefp.as_uint64 = hv_get_msr(HV_MSR_SIEFP);
304303
siefp.siefp_enabled = 1;
305304

@@ -328,6 +327,11 @@ void hv_hyp_synic_enable_regs(unsigned int cpu)
328327
shared_sint.masked = false;
329328
shared_sint.auto_eoi = hv_recommend_using_aeoi();
330329
hv_set_msr(HV_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
330+
}
331+
332+
static void hv_hyp_synic_enable_interrupts(void)
333+
{
334+
union hv_synic_scontrol sctrl;
331335

332336
/* Enable the global synic bit */
333337
sctrl.as_uint64 = hv_get_msr(HV_MSR_SCONTROL);
@@ -336,9 +340,59 @@ void hv_hyp_synic_enable_regs(unsigned int cpu)
336340
hv_set_msr(HV_MSR_SCONTROL, sctrl.as_uint64);
337341
}
338342

343+
static void hv_para_synic_enable_regs(unsigned int cpu)
344+
{
345+
union hv_synic_simp simp;
346+
union hv_synic_siefp siefp;
347+
struct hv_per_cpu_context *hv_cpu
348+
= per_cpu_ptr(hv_context.cpu_context, cpu);
349+
350+
/* Setup the Synic's message page with the paravisor. */
351+
simp.as_uint64 = hv_para_get_synic_register(HV_MSR_SIMP);
352+
simp.simp_enabled = 1;
353+
simp.base_simp_gpa = virt_to_phys(hv_cpu->para_synic_message_page)
354+
>> HV_HYP_PAGE_SHIFT;
355+
hv_para_set_synic_register(HV_MSR_SIMP, simp.as_uint64);
356+
357+
/* Setup the Synic's event page with the paravisor. */
358+
siefp.as_uint64 = hv_para_get_synic_register(HV_MSR_SIEFP);
359+
siefp.siefp_enabled = 1;
360+
siefp.base_siefp_gpa = virt_to_phys(hv_cpu->para_synic_event_page)
361+
>> HV_HYP_PAGE_SHIFT;
362+
hv_para_set_synic_register(HV_MSR_SIEFP, siefp.as_uint64);
363+
}
364+
365+
static void hv_para_synic_enable_interrupts(void)
366+
{
367+
union hv_synic_scontrol sctrl;
368+
369+
/* Enable the global synic bit */
370+
sctrl.as_uint64 = hv_para_get_synic_register(HV_MSR_SCONTROL);
371+
sctrl.enable = 1;
372+
hv_para_set_synic_register(HV_MSR_SCONTROL, sctrl.as_uint64);
373+
}
374+
339375
int hv_synic_init(unsigned int cpu)
340376
{
377+
if (vmbus_is_confidential())
378+
hv_para_synic_enable_regs(cpu);
379+
380+
/*
381+
* The SINT is set in hv_hyp_synic_enable_regs() by calling
382+
* hv_set_msr(). hv_set_msr() in turn has special case code for the
383+
* SINT MSRs that write to the hypervisor version of the MSR *and*
384+
* the paravisor version of the MSR (but *without* the proxy bit when
385+
* VMBus is confidential).
386+
*
387+
* Then enable interrupts via the paravisor if VMBus is confidential,
388+
* and otherwise via the hypervisor.
389+
*/
390+
341391
hv_hyp_synic_enable_regs(cpu);
392+
if (vmbus_is_confidential())
393+
hv_para_synic_enable_interrupts();
394+
else
395+
hv_hyp_synic_enable_interrupts();
342396

343397
hv_stimer_legacy_init(cpu, VMBUS_MESSAGE_SINT);
344398

@@ -352,7 +406,6 @@ void hv_hyp_synic_disable_regs(unsigned int cpu)
352406
union hv_synic_sint shared_sint;
353407
union hv_synic_simp simp;
354408
union hv_synic_siefp siefp;
355-
union hv_synic_scontrol sctrl;
356409

357410
shared_sint.as_uint64 = hv_get_msr(HV_MSR_SINT0 + VMBUS_MESSAGE_SINT);
358411

@@ -365,7 +418,7 @@ void hv_hyp_synic_disable_regs(unsigned int cpu)
365418

366419
simp.as_uint64 = hv_get_msr(HV_MSR_SIMP);
367420
/*
368-
* In Isolation VM, sim and sief pages are allocated by
421+
* In Isolation VM, simp and sief pages are allocated by
369422
* paravisor. These pages also will be used by kdump
370423
* kernel. So just reset enable bit here and keep page
371424
* addresses.
@@ -395,14 +448,42 @@ void hv_hyp_synic_disable_regs(unsigned int cpu)
395448
}
396449

397450
hv_set_msr(HV_MSR_SIEFP, siefp.as_uint64);
451+
}
452+
453+
static void hv_hyp_synic_disable_interrupts(void)
454+
{
455+
union hv_synic_scontrol sctrl;
398456

399457
/* Disable the global synic bit */
400458
sctrl.as_uint64 = hv_get_msr(HV_MSR_SCONTROL);
401459
sctrl.enable = 0;
402460
hv_set_msr(HV_MSR_SCONTROL, sctrl.as_uint64);
461+
}
403462

404-
if (vmbus_irq != -1)
405-
disable_percpu_irq(vmbus_irq);
463+
static void hv_para_synic_disable_regs(unsigned int cpu)
464+
{
465+
union hv_synic_simp simp;
466+
union hv_synic_siefp siefp;
467+
468+
/* Disable SynIC's message page in the paravisor. */
469+
simp.as_uint64 = hv_para_get_synic_register(HV_MSR_SIMP);
470+
simp.simp_enabled = 0;
471+
hv_para_set_synic_register(HV_MSR_SIMP, simp.as_uint64);
472+
473+
/* Disable SynIC's event page in the paravisor. */
474+
siefp.as_uint64 = hv_para_get_synic_register(HV_MSR_SIEFP);
475+
siefp.siefp_enabled = 0;
476+
hv_para_set_synic_register(HV_MSR_SIEFP, siefp.as_uint64);
477+
}
478+
479+
static void hv_para_synic_disable_interrupts(void)
480+
{
481+
union hv_synic_scontrol sctrl;
482+
483+
/* Disable the global synic bit */
484+
sctrl.as_uint64 = hv_para_get_synic_register(HV_MSR_SCONTROL);
485+
sctrl.enable = 0;
486+
hv_para_set_synic_register(HV_MSR_SCONTROL, sctrl.as_uint64);
406487
}
407488

408489
#define HV_MAX_TRIES 3
@@ -415,16 +496,18 @@ void hv_hyp_synic_disable_regs(unsigned int cpu)
415496
* that the normal interrupt handling mechanism will find and process the channel interrupt
416497
* "very soon", and in the process clear the bit.
417498
*/
418-
static bool hv_synic_event_pending(void)
499+
static bool __hv_synic_event_pending(union hv_synic_event_flags *event, int sint)
419500
{
420-
struct hv_per_cpu_context *hv_cpu = this_cpu_ptr(hv_context.cpu_context);
421-
union hv_synic_event_flags *event =
422-
(union hv_synic_event_flags *)hv_cpu->hyp_synic_event_page + VMBUS_MESSAGE_SINT;
423-
unsigned long *recv_int_page = event->flags; /* assumes VMBus version >= VERSION_WIN8 */
501+
unsigned long *recv_int_page;
424502
bool pending;
425503
u32 relid;
426504
int tries = 0;
427505

506+
if (!event)
507+
return false;
508+
509+
event += sint;
510+
recv_int_page = event->flags; /* assumes VMBus version >= VERSION_WIN8 */
428511
retry:
429512
pending = false;
430513
for_each_set_bit(relid, recv_int_page, HV_EVENT_FLAGS_COUNT) {
@@ -441,6 +524,17 @@ static bool hv_synic_event_pending(void)
441524
return pending;
442525
}
443526

527+
static bool hv_synic_event_pending(void)
528+
{
529+
struct hv_per_cpu_context *hv_cpu = this_cpu_ptr(hv_context.cpu_context);
530+
union hv_synic_event_flags *hyp_synic_event_page = hv_cpu->hyp_synic_event_page;
531+
union hv_synic_event_flags *para_synic_event_page = hv_cpu->para_synic_event_page;
532+
533+
return
534+
__hv_synic_event_pending(hyp_synic_event_page, VMBUS_MESSAGE_SINT) ||
535+
__hv_synic_event_pending(para_synic_event_page, VMBUS_MESSAGE_SINT);
536+
}
537+
444538
static int hv_pick_new_cpu(struct vmbus_channel *channel)
445539
{
446540
int ret = -EBUSY;
@@ -533,7 +627,27 @@ int hv_synic_cleanup(unsigned int cpu)
533627
always_cleanup:
534628
hv_stimer_legacy_cleanup(cpu);
535629

630+
/*
631+
* First, disable the event and message pages
632+
* used for communicating with the host, and then
633+
* disable the host interrupts if VMBus is not
634+
* confidential.
635+
*/
536636
hv_hyp_synic_disable_regs(cpu);
637+
if (!vmbus_is_confidential())
638+
hv_hyp_synic_disable_interrupts();
639+
640+
/*
641+
* Perform the same steps for the Confidential VMBus.
642+
* The sequencing provides the guarantee that no data
643+
* may be posted for processing before disabling interrupts.
644+
*/
645+
if (vmbus_is_confidential()) {
646+
hv_para_synic_disable_regs(cpu);
647+
hv_para_synic_disable_interrupts();
648+
}
649+
if (vmbus_irq != -1)
650+
disable_percpu_irq(vmbus_irq);
537651

538652
return ret;
539653
}

0 commit comments

Comments
 (0)