Skip to content

Commit 9857c55

Browse files
committed
x86/hv/mshv_vtl: Implement MAP_REDIRECTED_DEVICE_INTERRUPT
The MAP_REDIRECTED_DEVICE_INTERRUPT IOCTL maps an interrupt of a VTL0 guest to a hadware vector interrupt in the VTL2 kernel. On x86, we reserve a block of 32 vectors starting at FIRST_HV_VTL_ REDIRECTED_VECTOR for this mapping. Keep track of this redirection using an array hardware interrupt vectors and their mapping to a proxy interrupt, if any. Note that the array starts at zero but the first hardware vector is FIRST_HV_VTL_REDIRECTED_VECTOR. Account for this offset as needed. The array of mapped proxy interrupts is only updated when processing the IOCTL. It is only read during interrupts. Serialize access using a seqcount. This allows lockless read access for cases in which multiple CPUs want to access the mapping data structures. Since we are using a seqcount, writers cannot be preempted. Protect write access using a spinlock. Signed-off-by: Ricardo Neri <[email protected]> --- Changes since v1: * Used a seqcount for serialization.
1 parent 17e7171 commit 9857c55

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

arch/x86/kernel/cpu/mshyperv.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/irq.h>
1818
#include <linux/kexec.h>
1919
#include <linux/random.h>
20+
#include <linux/seqlock.h>
2021
#include <asm/processor.h>
2122
#include <asm/hypervisor.h>
2223
#include <asm/hyperv-tlfs.h>
@@ -166,6 +167,15 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_stimer0)
166167
}
167168

168169
#ifdef CONFIG_HYPERV_VTL_MODE
170+
#define REDIRECTED_VECTOR_UNDEF 0xffff
171+
static u32 redirected_proxy_intr[NR_HV_VTL_REDIRECTED_VECTORS] = {
172+
[0 ... NR_HV_VTL_REDIRECTED_VECTORS - 1] = REDIRECTED_VECTOR_UNDEF };
173+
174+
static DEFINE_RAW_SPINLOCK(redirected_proxy_intr_lock);
175+
static seqcount_raw_spinlock_t redirected_proxy_intr_seq =
176+
SEQCNT_RAW_SPINLOCK_ZERO(redirected_proxy_intr_seq,
177+
&redirected_proxy_intr_lock);
178+
169179
DEFINE_IDTENTRY_IRQ(hv_vtl_redirected_interrupt)
170180
{
171181
apic_eoi();
@@ -715,6 +725,83 @@ static bool hv_sev_es_hcall_finish(struct ghcb *ghcb, struct pt_regs *regs)
715725
}
716726
#endif
717727

728+
#ifdef CONFIG_HYPERV_VTL_MODE
729+
static int find_redirected_proxy_intr(u32 vector)
730+
{
731+
int v;
732+
733+
for (v = 0; v < ARRAY_SIZE(redirected_proxy_intr); v++) {
734+
if (redirected_proxy_intr[v] == vector)
735+
return v;
736+
}
737+
738+
return -ENOENT;
739+
}
740+
741+
static void redirected_proxy_intr_write_lock(unsigned long *flags)
742+
{
743+
raw_spin_lock_irqsave(&redirected_proxy_intr_lock, *flags);
744+
write_seqcount_begin(&redirected_proxy_intr_seq);
745+
}
746+
747+
static void redirected_proxy_intr_write_unlock(unsigned long *flags)
748+
{
749+
write_seqcount_end(&redirected_proxy_intr_seq);
750+
raw_spin_unlock_irqrestore(&redirected_proxy_intr_lock, *flags);
751+
}
752+
753+
int mshv_vtl_map_redirected_intr(u32 proxy_vector)
754+
{
755+
int vec_idx;
756+
unsigned long flags;
757+
758+
if (proxy_vector >= NR_VECTORS)
759+
return -EINVAL;
760+
761+
redirected_proxy_intr_write_lock(&flags);
762+
763+
/* Check if the vector is already redirected. */
764+
vec_idx = find_redirected_proxy_intr(proxy_vector);
765+
if (vec_idx >= 0) {
766+
redirected_proxy_intr_write_unlock(&flags);
767+
/* Caller expects the hardware vector, not the array index. */
768+
return vec_idx + FIRST_HV_VTL_REDIRECTED_VECTOR;
769+
}
770+
771+
/* Now that we know it is not redirected, find a free slot. */
772+
vec_idx = find_redirected_proxy_intr(REDIRECTED_VECTOR_UNDEF);
773+
if (vec_idx < 0) {
774+
redirected_proxy_intr_write_unlock(&flags);
775+
return -EBUSY;
776+
}
777+
778+
redirected_proxy_intr[vec_idx] = proxy_vector;
779+
780+
redirected_proxy_intr_write_unlock(&flags);
781+
782+
/* Caller expects the hardware vector, not the array index. */
783+
return vec_idx + FIRST_HV_VTL_REDIRECTED_VECTOR;
784+
}
785+
786+
int mshv_vtl_unmap_redirected_intr(u32 hw_vector)
787+
{
788+
unsigned long flags;
789+
int vec_idx = hw_vector - FIRST_HV_VTL_REDIRECTED_VECTOR;
790+
791+
if (vec_idx < 0 || vec_idx >= ARRAY_SIZE(redirected_proxy_intr))
792+
return -EINVAL;
793+
794+
if (redirected_proxy_intr[vec_idx] == REDIRECTED_VECTOR_UNDEF)
795+
return -ENOENT;
796+
797+
redirected_proxy_intr_write_lock(&flags);
798+
redirected_proxy_intr[vec_idx] = REDIRECTED_VECTOR_UNDEF;
799+
redirected_proxy_intr_write_unlock(&flags);
800+
801+
return 0;
802+
}
803+
#endif /* CONFIG_HYPERV_VTL_MODE */
804+
718805
const __initconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
719806
.name = "Microsoft Hyper-V",
720807
.detect = ms_hyperv_platform,

0 commit comments

Comments
 (0)