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
2224static int synic_cpuhp_online ;
2325static 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
2529static 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+
686777int __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 );
714810free_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}
0 commit comments