Skip to content

Commit 622d687

Browse files
Anirudh Rayabharam (Microsoft)liuw
authored andcommitted
mshv: add arm64 support for doorbell & intercept SINTs
On x86, the HYPERVISOR_CALLBACK_VECTOR is used to receive synthetic interrupts (SINTs) from the hypervisor for doorbells and intercepts. There is no such vector reserved for arm64. On arm64, the hypervisor exposes a synthetic register that can be read to find the INTID that should be used for SINTs. This INTID is in the PPI range. To better unify the code paths, introduce mshv_sint_vector_init() that either reads the synthetic register and obtains the INTID (arm64) or just uses HYPERVISOR_CALLBACK_VECTOR as the interrupt vector (x86). Reviewed-by: Michael Kelley <mhklinux@outlook.com> Reviewed-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com> Signed-off-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com> Signed-off-by: Wei Liu <wei.liu@kernel.org>
1 parent 5a674ef commit 622d687

2 files changed

Lines changed: 111 additions & 10 deletions

File tree

drivers/hv/mshv_synic.c

Lines changed: 109 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,21 @@
1010
#include <linux/kernel.h>
1111
#include <linux/slab.h>
1212
#include <linux/mm.h>
13+
#include <linux/interrupt.h>
1314
#include <linux/io.h>
1415
#include <linux/random.h>
1516
#include <linux/cpuhotplug.h>
1617
#include <linux/reboot.h>
1718
#include <asm/mshyperv.h>
19+
#include <linux/acpi.h>
1820

1921
#include "mshv_eventfd.h"
2022
#include "mshv.h"
2123

2224
static int synic_cpuhp_online;
2325
static struct hv_synic_pages __percpu *synic_pages;
26+
static int mshv_sint_vector = -1; /* hwirq for the SynIC SINTs */
27+
static int mshv_sint_irq = -1; /* Linux IRQ for mshv_sint_vector */
2428

2529
static u32 synic_event_ring_get_queued_port(u32 sint_index)
2630
{
@@ -442,9 +446,7 @@ void mshv_isr(void)
442446
if (msg->header.message_flags.msg_pending)
443447
hv_set_non_nested_msr(HV_MSR_EOM, 0);
444448

445-
#ifdef HYPERVISOR_CALLBACK_VECTOR
446-
add_interrupt_randomness(HYPERVISOR_CALLBACK_VECTOR);
447-
#endif
449+
add_interrupt_randomness(mshv_sint_vector);
448450
} else {
449451
pr_warn_once("%s: unknown message type 0x%x\n", __func__,
450452
msg->header.message_type);
@@ -456,9 +458,7 @@ static int mshv_synic_cpu_init(unsigned int cpu)
456458
union hv_synic_simp simp;
457459
union hv_synic_siefp siefp;
458460
union hv_synic_sirbp sirbp;
459-
#ifdef HYPERVISOR_CALLBACK_VECTOR
460461
union hv_synic_sint sint;
461-
#endif
462462
union hv_synic_scontrol sctrl;
463463
struct hv_synic_pages *spages = this_cpu_ptr(synic_pages);
464464
struct hv_message_page **msg_page = &spages->hyp_synic_message_page;
@@ -501,24 +501,25 @@ static int mshv_synic_cpu_init(unsigned int cpu)
501501

502502
hv_set_non_nested_msr(HV_MSR_SIRBP, sirbp.as_uint64);
503503

504-
#ifdef HYPERVISOR_CALLBACK_VECTOR
504+
if (mshv_sint_irq != -1)
505+
enable_percpu_irq(mshv_sint_irq, 0);
506+
505507
/* Enable intercepts */
506508
sint.as_uint64 = 0;
507-
sint.vector = HYPERVISOR_CALLBACK_VECTOR;
509+
sint.vector = mshv_sint_vector;
508510
sint.masked = false;
509511
sint.auto_eoi = hv_recommend_using_aeoi();
510512
hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX,
511513
sint.as_uint64);
512514

513515
/* Doorbell SINT */
514516
sint.as_uint64 = 0;
515-
sint.vector = HYPERVISOR_CALLBACK_VECTOR;
517+
sint.vector = mshv_sint_vector;
516518
sint.masked = false;
517519
sint.as_intercept = 1;
518520
sint.auto_eoi = hv_recommend_using_aeoi();
519521
hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_DOORBELL_SINT_INDEX,
520522
sint.as_uint64);
521-
#endif
522523

523524
/* Enable global synic bit */
524525
sctrl.as_uint64 = hv_get_non_nested_msr(HV_MSR_SCONTROL);
@@ -573,6 +574,9 @@ static int mshv_synic_cpu_exit(unsigned int cpu)
573574
hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_DOORBELL_SINT_INDEX,
574575
sint.as_uint64);
575576

577+
if (mshv_sint_irq != -1)
578+
disable_percpu_irq(mshv_sint_irq);
579+
576580
/* Disable Synic's event ring page */
577581
sirbp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIRBP);
578582
sirbp.sirbp_enabled = false;
@@ -683,14 +687,106 @@ static struct notifier_block mshv_synic_reboot_nb = {
683687
.notifier_call = mshv_synic_reboot_notify,
684688
};
685689

690+
#ifndef HYPERVISOR_CALLBACK_VECTOR
691+
static DEFINE_PER_CPU(long, mshv_evt);
692+
693+
static irqreturn_t mshv_percpu_isr(int irq, void *dev_id)
694+
{
695+
mshv_isr();
696+
return IRQ_HANDLED;
697+
}
698+
699+
#ifdef CONFIG_ACPI
700+
static int __init mshv_acpi_setup_sint_irq(void)
701+
{
702+
return acpi_register_gsi(NULL, mshv_sint_vector, ACPI_EDGE_SENSITIVE,
703+
ACPI_ACTIVE_HIGH);
704+
}
705+
706+
static void mshv_acpi_cleanup_sint_irq(void)
707+
{
708+
acpi_unregister_gsi(mshv_sint_vector);
709+
}
710+
#else
711+
static int __init mshv_acpi_setup_sint_irq(void)
712+
{
713+
return -ENODEV;
714+
}
715+
716+
static void mshv_acpi_cleanup_sint_irq(void)
717+
{
718+
}
719+
#endif
720+
721+
static int __init mshv_sint_vector_setup(void)
722+
{
723+
int ret;
724+
struct hv_register_assoc reg = {
725+
.name = HV_ARM64_REGISTER_SINT_RESERVED_INTERRUPT_ID,
726+
};
727+
union hv_input_vtl input_vtl = { 0 };
728+
729+
if (acpi_disabled)
730+
return -ENODEV;
731+
732+
ret = hv_call_get_vp_registers(HV_VP_INDEX_SELF, HV_PARTITION_ID_SELF,
733+
1, input_vtl, &reg);
734+
if (ret || !reg.value.reg64)
735+
return -ENODEV;
736+
737+
mshv_sint_vector = reg.value.reg64;
738+
ret = mshv_acpi_setup_sint_irq();
739+
if (ret < 0) {
740+
pr_err("Failed to setup IRQ for MSHV SINT vector %d: %d\n",
741+
mshv_sint_vector, ret);
742+
goto out_fail;
743+
}
744+
745+
mshv_sint_irq = ret;
746+
747+
ret = request_percpu_irq(mshv_sint_irq, mshv_percpu_isr, "MSHV",
748+
&mshv_evt);
749+
if (ret)
750+
goto out_unregister;
751+
752+
return 0;
753+
754+
out_unregister:
755+
mshv_acpi_cleanup_sint_irq();
756+
out_fail:
757+
return ret;
758+
}
759+
760+
static void mshv_sint_vector_cleanup(void)
761+
{
762+
free_percpu_irq(mshv_sint_irq, &mshv_evt);
763+
mshv_acpi_cleanup_sint_irq();
764+
}
765+
#else /* !HYPERVISOR_CALLBACK_VECTOR */
766+
static int __init mshv_sint_vector_setup(void)
767+
{
768+
mshv_sint_vector = HYPERVISOR_CALLBACK_VECTOR;
769+
return 0;
770+
}
771+
772+
static void mshv_sint_vector_cleanup(void)
773+
{
774+
}
775+
#endif /* HYPERVISOR_CALLBACK_VECTOR */
776+
686777
int __init mshv_synic_init(struct device *dev)
687778
{
688779
int ret = 0;
689780

781+
ret = mshv_sint_vector_setup();
782+
if (ret)
783+
return ret;
784+
690785
synic_pages = alloc_percpu(struct hv_synic_pages);
691786
if (!synic_pages) {
692787
dev_err(dev, "Failed to allocate percpu synic page\n");
693-
return -ENOMEM;
788+
ret = -ENOMEM;
789+
goto sint_vector_cleanup;
694790
}
695791

696792
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mshv_synic",
@@ -713,6 +809,8 @@ int __init mshv_synic_init(struct device *dev)
713809
cpuhp_remove_state(synic_cpuhp_online);
714810
free_synic_pages:
715811
free_percpu(synic_pages);
812+
sint_vector_cleanup:
813+
mshv_sint_vector_cleanup();
716814
return ret;
717815
}
718816

@@ -721,4 +819,5 @@ void mshv_synic_exit(void)
721819
unregister_reboot_notifier(&mshv_synic_reboot_nb);
722820
cpuhp_remove_state(synic_cpuhp_online);
723821
free_percpu(synic_pages);
822+
mshv_sint_vector_cleanup();
724823
}

include/hyperv/hvgdk_mini.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,8 @@ enum hv_register_name {
11211121
HV_X64_REGISTER_MSR_MTRR_FIX4KF8000 = 0x0008007A,
11221122

11231123
HV_X64_REGISTER_REG_PAGE = 0x0009001C,
1124+
#elif defined(CONFIG_ARM64)
1125+
HV_ARM64_REGISTER_SINT_RESERVED_INTERRUPT_ID = 0x00070001,
11241126
#endif
11251127
};
11261128

0 commit comments

Comments
 (0)