Skip to content

Commit c9dd310

Browse files
donshengwenlingz
authored andcommitted
hv: check if the IRQ is intended for a single destination vCPU
Given the vcpumask, check if the IRQ is single destination and return the destination vCPU if so, the address of associated PI descriptor for this vCPU can then be passed to dmar_assign_irte() to set up the posted interrupt IRTE for this device. For fixed mode interrupt delivery, all vCPUs listed in vcpumask should service the interrupt requested. But VT-d PI cannot support multicast/broadcast IRQs, it only supports single CPU destination. So the number of vCPUs shall be 1 in order to handle IRQ in posted mode for this device. Add pid_paddr to struct intr_source. If platform_caps.pi is true and the IRQ is single-destination, pass the physical address of the destination vCPU's PID to ptirq_build_physical_msi and dmar_assign_irte Tracked-On: #4506 Signed-off-by: dongshen <dongsheng.x.zhang@intel.com> Reviewed-by: Eddie Dong <eddie.dong@Intel.com>
1 parent 198b257 commit c9dd310

File tree

2 files changed

+63
-4
lines changed

2 files changed

+63
-4
lines changed

hypervisor/arch/x86/guest/assign.c

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,42 @@
1212
#include <ptdev.h>
1313
#include <per_cpu.h>
1414
#include <ioapic.h>
15+
#include <pgtable.h>
16+
17+
/*
18+
* Check if the IRQ is single-destination and return the destination vCPU if so.
19+
*
20+
* VT-d PI (posted mode) cannot support multicast/broadcast IRQs.
21+
* If returns NULL, this means it is multicast/broadcast IRQ and
22+
* we can only handle it in remapped mode.
23+
* If returns non-NULL, the destination vCPU is returned, which means it is
24+
* single-destination IRQ and we can handle it in posted mode.
25+
*
26+
* @pre (vm != NULL) && (info != NULL)
27+
*/
28+
static struct acrn_vcpu *is_single_destination(struct acrn_vm *vm, const struct ptirq_msi_info *info)
29+
{
30+
uint64_t vdmask;
31+
uint16_t vid;
32+
struct acrn_vcpu *vcpu = NULL;
33+
34+
vlapic_calc_dest(vm, &vdmask, false, (uint32_t)(info->vmsi_addr.bits.dest_field),
35+
(bool)(info->vmsi_addr.bits.dest_mode == MSI_ADDR_DESTMODE_PHYS),
36+
(bool)(info->vmsi_data.bits.delivery_mode == MSI_DATA_DELMODE_LOPRI));
37+
38+
vid = ffs64(vdmask);
39+
40+
/* Can only post fixed and Lowpri IRQs */
41+
if ((info->vmsi_data.bits.delivery_mode == MSI_DATA_DELMODE_FIXED)
42+
|| (info->vmsi_data.bits.delivery_mode == MSI_DATA_DELMODE_LOPRI)) {
43+
/* Can only post single-destination IRQs */
44+
if (vdmask == (1UL << vid)) {
45+
vcpu = vcpu_from_vid(vm, vid);
46+
}
47+
}
48+
49+
return vcpu;
50+
}
1551

1652
/*
1753
* lookup a ptdev entry by sid
@@ -80,8 +116,14 @@ static void ptirq_free_irte(const struct ptirq_remapping_info *entry)
80116
dmar_free_irte(&intr_src, (uint16_t)entry->allocated_pirq);
81117
}
82118

119+
/*
120+
* pid_paddr = 0: invalid address, indicate that remapped mode shall be used
121+
*
122+
* pid_paddr != 0: physical address of posted interrupt descriptor, indicate
123+
* that posted mode shall be used
124+
*/
83125
static void ptirq_build_physical_msi(struct acrn_vm *vm, struct ptirq_msi_info *info,
84-
const struct ptirq_remapping_info *entry, uint32_t vector)
126+
const struct ptirq_remapping_info *entry, uint32_t vector, uint64_t pid_paddr)
85127
{
86128
uint64_t vdmask, pdmask;
87129
uint32_t dest, delmode, dest_mask;
@@ -116,6 +158,7 @@ static void ptirq_build_physical_msi(struct acrn_vm *vm, struct ptirq_msi_info *
116158
irte.bits.remap.dest = dest_mask;
117159

118160
intr_src.is_msi = true;
161+
intr_src.pid_paddr = pid_paddr;
119162
intr_src.src.msi.value = entry->phys_sid.msi_id.bdf;
120163
ret = dmar_assign_irte(&intr_src, &irte, (uint16_t)entry->allocated_pirq);
121164

@@ -212,6 +255,7 @@ ptirq_build_physical_rte(struct acrn_vm *vm, struct ptirq_remapping_info *entry)
212255
irte.bits.remap.trigger_mode = rte.bits.trigger_mode;
213256

214257
intr_src.is_msi = false;
258+
intr_src.pid_paddr = 0UL;
215259
intr_src.src.ioapic_id = ioapic_irq_to_ioapic_id(phys_irq);
216260
ret = dmar_assign_irte(&intr_src, &irte, (uint16_t)phys_irq);
217261

@@ -606,13 +650,13 @@ int32_t ptirq_prepare_msix_remap(struct acrn_vm *vm, uint16_t virt_bdf, uint16_t
606650
* All the vCPUs are in x2APIC mode and LAPIC is Pass-through
607651
* Use guest vector to program the interrupt source
608652
*/
609-
ptirq_build_physical_msi(vm, info, entry, (uint32_t)info->vmsi_data.bits.vector);
653+
ptirq_build_physical_msi(vm, info, entry, (uint32_t)info->vmsi_data.bits.vector, 0UL);
610654
} else if (vlapic_state == VM_VLAPIC_XAPIC) {
611655
/*
612656
* All the vCPUs are in xAPIC mode and LAPIC is emulated
613657
* Use host vector to program the interrupt source
614658
*/
615-
ptirq_build_physical_msi(vm, info, entry, irq_to_vector(entry->allocated_pirq));
659+
ptirq_build_physical_msi(vm, info, entry, irq_to_vector(entry->allocated_pirq), 0UL);
616660
} else if (vlapic_state == VM_VLAPIC_TRANSITION) {
617661
/*
618662
* vCPUs are in middle of transition, so do not program interrupt source
@@ -626,7 +670,15 @@ int32_t ptirq_prepare_msix_remap(struct acrn_vm *vm, uint16_t virt_bdf, uint16_t
626670
ret = -EFAULT;
627671
}
628672
} else {
629-
ptirq_build_physical_msi(vm, info, entry, irq_to_vector(entry->allocated_pirq));
673+
struct acrn_vcpu *vcpu = is_single_destination(vm, info);
674+
675+
if (is_pi_capable(vm) && (vcpu != NULL)) {
676+
ptirq_build_physical_msi(vm, info, entry,
677+
(uint32_t)info->vmsi_data.bits.vector, hva2hpa(get_pi_desc(vcpu)));
678+
} else {
679+
/* Go with remapped mode if we cannot handle it in posted mode */
680+
ptirq_build_physical_msi(vm, info, entry, irq_to_vector(entry->allocated_pirq), 0UL);
681+
}
630682
}
631683

632684
if (ret == 0) {

hypervisor/include/arch/x86/vtd.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@ union source {
6969
struct intr_source {
7070
bool is_msi;
7171
union source src;
72+
/*
73+
* pid_paddr = 0: invalid address, indicate that remapped mode shall be used
74+
*
75+
* pid_paddr != 0: physical address of posted interrupt descriptor, indicate
76+
* that posted mode shall be used
77+
*/
78+
uint64_t pid_paddr;
7279
};
7380

7481
static inline uint8_t dmar_ver_major(uint64_t version)

0 commit comments

Comments
 (0)