hv: ptirq: associate an irte with ptirq_remapping_info entry

For a ptirq_remapping_info entry, when build IRTE:
- If the caller provides a valid IRTE, use the IRET
- If the caller doesn't provide a valid IRTE, allocate a IRET when the
entry doesn't have a valid IRTE, in this case, the IRET will be freed
when free the entry.

Tracked-On:#4831
Signed-off-by: Binbin Wu <binbin.wu@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Binbin Wu 2020-05-10 09:29:53 +00:00 committed by wenlingz
parent 2fe4280cfa
commit 7bfcc673a6
7 changed files with 47 additions and 22 deletions

View File

@ -71,15 +71,16 @@ static void ptirq_free_irte(const struct ptirq_remapping_info *entry)
{ {
struct intr_source intr_src; struct intr_source intr_src;
if (entry->intr_type == PTDEV_INTR_MSI) { if (entry->irte_idx < CONFIG_MAX_IR_ENTRIES) {
intr_src.is_msi = true; if (entry->intr_type == PTDEV_INTR_MSI) {
intr_src.src.msi.value = entry->phys_sid.msi_id.bdf; intr_src.is_msi = true;
} else { intr_src.src.msi.value = entry->phys_sid.msi_id.bdf;
intr_src.is_msi = false; } else {
intr_src.src.ioapic_id = ioapic_irq_to_ioapic_id(entry->allocated_pirq); intr_src.is_msi = false;
intr_src.src.ioapic_id = ioapic_irq_to_ioapic_id(entry->allocated_pirq);
}
dmar_free_irte(&intr_src, entry->irte_idx);
} }
dmar_free_irte(&intr_src, (uint16_t)entry->allocated_pirq);
} }
/* /*
@ -89,7 +90,7 @@ static void ptirq_free_irte(const struct ptirq_remapping_info *entry)
* that posted mode shall be used * that posted mode shall be used
*/ */
static void ptirq_build_physical_msi(struct acrn_vm *vm, static void ptirq_build_physical_msi(struct acrn_vm *vm,
struct ptirq_remapping_info *entry, uint32_t vector, uint64_t pid_paddr) struct ptirq_remapping_info *entry, uint32_t vector, uint64_t pid_paddr, uint16_t irte_idx)
{ {
uint64_t vdmask, pdmask; uint64_t vdmask, pdmask;
uint32_t dest, delmode, dest_mask; uint32_t dest, delmode, dest_mask;
@ -126,11 +127,15 @@ static void ptirq_build_physical_msi(struct acrn_vm *vm,
intr_src.is_msi = true; intr_src.is_msi = true;
intr_src.pid_paddr = pid_paddr; intr_src.pid_paddr = pid_paddr;
intr_src.src.msi.value = entry->phys_sid.msi_id.bdf; intr_src.src.msi.value = entry->phys_sid.msi_id.bdf;
ret = dmar_assign_irte(&intr_src, &irte, (uint16_t)entry->allocated_pirq, &ir_index.index); if (entry->irte_idx == INVALID_IRTE_ID) {
entry->irte_idx = irte_idx;
}
ret = dmar_assign_irte(&intr_src, &irte, entry->irte_idx, &ir_index.index);
if (ret == 0) { if (ret == 0) {
entry->pmsi.data.full = 0U; entry->pmsi.data.full = 0U;
entry->pmsi.addr.full = 0UL; entry->pmsi.addr.full = 0UL;
entry->irte_idx = ir_index.index;
if (ir_index.index != INVALID_IRTE_ID) { if (ir_index.index != INVALID_IRTE_ID) {
/* /*
* Update the MSI interrupt source to point to the IRTE * Update the MSI interrupt source to point to the IRTE
@ -223,9 +228,10 @@ ptirq_build_physical_rte(struct acrn_vm *vm, struct ptirq_remapping_info *entry)
intr_src.is_msi = false; intr_src.is_msi = false;
intr_src.pid_paddr = 0UL; intr_src.pid_paddr = 0UL;
intr_src.src.ioapic_id = ioapic_irq_to_ioapic_id(phys_irq); intr_src.src.ioapic_id = ioapic_irq_to_ioapic_id(phys_irq);
ret = dmar_assign_irte(&intr_src, &irte, (uint16_t)phys_irq, &ir_index.index); ret = dmar_assign_irte(&intr_src, &irte, entry->irte_idx, &ir_index.index);
if (ret == 0) { if (ret == 0) {
entry->irte_idx = ir_index.index;
if (ir_index.index != INVALID_IRTE_ID) { if (ir_index.index != INVALID_IRTE_ID) {
rte.ir_bits.vector = vector; rte.ir_bits.vector = vector;
rte.ir_bits.constant = 0U; rte.ir_bits.constant = 0U;
@ -319,7 +325,7 @@ remove_msix_remapping(const struct acrn_vm *vm, uint16_t phys_bdf, uint32_t entr
intr_src.is_msi = true; intr_src.is_msi = true;
intr_src.src.msi.value = entry->phys_sid.msi_id.bdf; intr_src.src.msi.value = entry->phys_sid.msi_id.bdf;
dmar_free_irte(&intr_src, (uint16_t)entry->allocated_pirq); dmar_free_irte(&intr_src, entry->irte_idx);
dev_dbg(DBG_LEVEL_IRQ, "VM%d MSIX remove vector mapping vbdf-pbdf:0x%x-0x%x idx=%d", dev_dbg(DBG_LEVEL_IRQ, "VM%d MSIX remove vector mapping vbdf-pbdf:0x%x-0x%x idx=%d",
vm->vm_id, entry->virt_sid.msi_id.bdf, phys_bdf, entry_nr); vm->vm_id, entry->virt_sid.msi_id.bdf, phys_bdf, entry_nr);
@ -408,7 +414,7 @@ static void remove_intx_remapping(const struct acrn_vm *vm, uint32_t virt_gsi, e
intr_src.is_msi = false; intr_src.is_msi = false;
intr_src.src.ioapic_id = ioapic_irq_to_ioapic_id(phys_irq); intr_src.src.ioapic_id = ioapic_irq_to_ioapic_id(phys_irq);
dmar_free_irte(&intr_src, (uint16_t)phys_irq); dmar_free_irte(&intr_src, entry->irte_idx);
dev_dbg(DBG_LEVEL_IRQ, dev_dbg(DBG_LEVEL_IRQ,
"deactive %s intx entry:pgsi=%d, pirq=%d ", "deactive %s intx entry:pgsi=%d, pirq=%d ",
(vgsi_ctlr == INTX_CTLR_PIC) ? "vPIC" : "vIOAPIC", (vgsi_ctlr == INTX_CTLR_PIC) ? "vPIC" : "vIOAPIC",
@ -563,7 +569,7 @@ void ptirq_intx_ack(struct acrn_vm *vm, uint32_t virt_gsi, enum intx_ctlr vgsi_c
* user must provide bdf and entry_nr * user must provide bdf and entry_nr
*/ */
int32_t ptirq_prepare_msix_remap(struct acrn_vm *vm, uint16_t virt_bdf, uint16_t phys_bdf, int32_t ptirq_prepare_msix_remap(struct acrn_vm *vm, uint16_t virt_bdf, uint16_t phys_bdf,
uint16_t entry_nr, struct msi_info *info) uint16_t entry_nr, struct msi_info *info, uint16_t irte_idx)
{ {
struct ptirq_remapping_info *entry; struct ptirq_remapping_info *entry;
int32_t ret = -ENODEV; int32_t ret = -ENODEV;
@ -590,13 +596,13 @@ int32_t ptirq_prepare_msix_remap(struct acrn_vm *vm, uint16_t virt_bdf, uint16_t
* All the vCPUs are in x2APIC mode and LAPIC is Pass-through * All the vCPUs are in x2APIC mode and LAPIC is Pass-through
* Use guest vector to program the interrupt source * Use guest vector to program the interrupt source
*/ */
ptirq_build_physical_msi(vm, entry, (uint32_t)info->data.bits.vector, 0UL); ptirq_build_physical_msi(vm, entry, (uint32_t)info->data.bits.vector, 0UL, irte_idx);
} else if (vlapic_state == VM_VLAPIC_XAPIC) { } else if (vlapic_state == VM_VLAPIC_XAPIC) {
/* /*
* All the vCPUs are in xAPIC mode and LAPIC is emulated * All the vCPUs are in xAPIC mode and LAPIC is emulated
* Use host vector to program the interrupt source * Use host vector to program the interrupt source
*/ */
ptirq_build_physical_msi(vm, entry, irq_to_vector(entry->allocated_pirq), 0UL); ptirq_build_physical_msi(vm, entry, irq_to_vector(entry->allocated_pirq), 0UL, irte_idx);
} else if (vlapic_state == VM_VLAPIC_TRANSITION) { } else if (vlapic_state == VM_VLAPIC_TRANSITION) {
/* /*
* vCPUs are in middle of transition, so do not program interrupt source * vCPUs are in middle of transition, so do not program interrupt source
@ -614,10 +620,10 @@ int32_t ptirq_prepare_msix_remap(struct acrn_vm *vm, uint16_t virt_bdf, uint16_t
if (is_pi_capable(vm) && (vcpu != NULL)) { if (is_pi_capable(vm) && (vcpu != NULL)) {
ptirq_build_physical_msi(vm, entry, ptirq_build_physical_msi(vm, entry,
(uint32_t)info->data.bits.vector, hva2hpa(get_pi_desc(vcpu))); (uint32_t)info->data.bits.vector, hva2hpa(get_pi_desc(vcpu)), irte_idx);
} else { } else {
/* Go with remapped mode if we cannot handle it in posted mode */ /* Go with remapped mode if we cannot handle it in posted mode */
ptirq_build_physical_msi(vm, entry, irq_to_vector(entry->allocated_pirq), 0UL); ptirq_build_physical_msi(vm, entry, irq_to_vector(entry->allocated_pirq), 0UL, irte_idx);
} }
} }

View File

@ -128,7 +128,8 @@ struct dmar_drhd_rt {
uint64_t root_table_addr; uint64_t root_table_addr;
uint64_t ir_table_addr; uint64_t ir_table_addr;
uint64_t irte_alloc_bitmap[CONFIG_MAX_IR_ENTRIES/64U]; uint64_t irte_alloc_bitmap[CONFIG_MAX_IR_ENTRIES / 64U];
uint64_t irte_reserved_bitmap[CONFIG_MAX_IR_ENTRIES / 64U];
uint64_t qi_queue; uint64_t qi_queue;
uint16_t qi_tail; uint16_t qi_tail;
@ -1284,6 +1285,11 @@ static uint16_t alloc_irtes(struct dmar_drhd_rt *dmar_unit, const uint16_t num)
return (irte_idx < CONFIG_MAX_IR_ENTRIES) ? irte_idx: INVALID_IRTE_ID; return (irte_idx < CONFIG_MAX_IR_ENTRIES) ? irte_idx: INVALID_IRTE_ID;
} }
static bool is_irte_reserved(const struct dmar_drhd_rt *dmar_unit, uint16_t index)
{
return ((dmar_unit->irte_reserved_bitmap[index >> 6U] & (1UL << (index & 0x3FU))) != 0UL);
}
int32_t dmar_assign_irte(const struct intr_source *intr_src, union dmar_ir_entry *irte, int32_t dmar_assign_irte(const struct intr_source *intr_src, union dmar_ir_entry *irte,
uint16_t idx_in, uint16_t *idx_out) uint16_t idx_in, uint16_t *idx_out)
{ {
@ -1368,6 +1374,12 @@ void dmar_free_irte(const struct intr_source *intr_src, uint16_t index)
iommu_flush_cache(ir_entry, sizeof(union dmar_ir_entry)); iommu_flush_cache(ir_entry, sizeof(union dmar_ir_entry));
dmar_invalid_iec(dmar_unit, index, 0U, false); dmar_invalid_iec(dmar_unit, index, 0U, false);
if (!is_irte_reserved(dmar_unit, index)) {
spinlock_obtain(&dmar_unit->lock);
bitmap_clear_nolock(index & 0x3FU, &dmar_unit->irte_alloc_bitmap[index >> 6U]);
spinlock_release(&dmar_unit->lock);
}
} }
} }

View File

@ -11,6 +11,7 @@
#include <ptdev.h> #include <ptdev.h>
#include <irq.h> #include <irq.h>
#include <logmsg.h> #include <logmsg.h>
#include <vtd.h>
#define PTIRQ_ENTRY_HASHBITS 9U #define PTIRQ_ENTRY_HASHBITS 9U
#define PTIRQ_ENTRY_HASHSIZE (1U << PTIRQ_ENTRY_HASHBITS) #define PTIRQ_ENTRY_HASHSIZE (1U << PTIRQ_ENTRY_HASHBITS)
@ -127,6 +128,7 @@ struct ptirq_remapping_info *ptirq_alloc_entry(struct acrn_vm *vm, uint32_t intr
entry->intr_type = intr_type; entry->intr_type = intr_type;
entry->vm = vm; entry->vm = vm;
entry->intr_count = 0UL; entry->intr_count = 0UL;
entry->irte_idx = INVALID_IRTE_ID;
INIT_LIST_HEAD(&entry->softirq_node); INIT_LIST_HEAD(&entry->softirq_node);

View File

@ -31,6 +31,7 @@
#include <ptdev.h> #include <ptdev.h>
#include <assign.h> #include <assign.h>
#include <vpci.h> #include <vpci.h>
#include <vtd.h>
#include "vpci_priv.h" #include "vpci_priv.h"
@ -78,7 +79,7 @@ static void remap_vmsi(const struct pci_vdev *vdev)
info.addr.full = (uint64_t)vmsi_addrlo | ((uint64_t)vmsi_addrhi << 32U); info.addr.full = (uint64_t)vmsi_addrlo | ((uint64_t)vmsi_addrhi << 32U);
info.data.full = vmsi_msgdata; info.data.full = vmsi_msgdata;
if (ptirq_prepare_msix_remap(vm, vdev->bdf.value, pbdf.value, 0U, &info) == 0) { if (ptirq_prepare_msix_remap(vm, vdev->bdf.value, pbdf.value, 0U, &info, INVALID_IRTE_ID) == 0) {
pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_ADDR, 0x4U, (uint32_t)info.addr.full); pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_ADDR, 0x4U, (uint32_t)info.addr.full);
if (vdev->msi.is_64bit) { if (vdev->msi.is_64bit) {
pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_ADDR_HIGH, 0x4U, pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_ADDR_HIGH, 0x4U,

View File

@ -36,6 +36,7 @@
#include <ept.h> #include <ept.h>
#include <mmu.h> #include <mmu.h>
#include <logmsg.h> #include <logmsg.h>
#include <vtd.h>
#include "vpci_priv.h" #include "vpci_priv.h"
/** /**
@ -87,7 +88,8 @@ static void remap_one_vmsix_entry(const struct pci_vdev *vdev, uint32_t index)
info.addr.full = vdev->msix.table_entries[index].addr; info.addr.full = vdev->msix.table_entries[index].addr;
info.data.full = vdev->msix.table_entries[index].data; info.data.full = vdev->msix.table_entries[index].data;
ret = ptirq_prepare_msix_remap(vpci2vm(vdev->vpci), vdev->bdf.value, vdev->pdev->bdf.value, (uint16_t)index, &info); ret = ptirq_prepare_msix_remap(vpci2vm(vdev->vpci), vdev->bdf.value, vdev->pdev->bdf.value,
(uint16_t)index, &info, INVALID_IRTE_ID);
if (ret == 0) { if (ret == 0) {
/* Write the table entry to the physical structure */ /* Write the table entry to the physical structure */
pentry = get_msix_table_entry(vdev, index); pentry = get_msix_table_entry(vdev, index);

View File

@ -50,6 +50,7 @@ void ptirq_intx_ack(struct acrn_vm *vm, uint32_t virt_gsi, enum intx_ctlr vgsi_c
* @param[in] phys_bdf virtual bdf associated with the passthrough device * @param[in] phys_bdf virtual bdf associated with the passthrough device
* @param[in] entry_nr indicate coming vectors, entry_nr = 0 means first vector * @param[in] entry_nr indicate coming vectors, entry_nr = 0 means first vector
* @param[in] info structure used for MSI/MSI-x remapping * @param[in] info structure used for MSI/MSI-x remapping
* @param[in] irte_idx caller can pass a valid IRTE index, otherwise, use INVALID_IRTE_ID
* *
* @return * @return
* - 0: on success * - 0: on success
@ -62,7 +63,7 @@ void ptirq_intx_ack(struct acrn_vm *vm, uint32_t virt_gsi, enum intx_ctlr vgsi_c
* *
*/ */
int32_t ptirq_prepare_msix_remap(struct acrn_vm *vm, uint16_t virt_bdf, uint16_t phys_bdf, int32_t ptirq_prepare_msix_remap(struct acrn_vm *vm, uint16_t virt_bdf, uint16_t phys_bdf,
uint16_t entry_nr, struct msi_info *info); uint16_t entry_nr, struct msi_info *info, uint16_t irte_idx);
/** /**

View File

@ -133,6 +133,7 @@ struct ptirq_remapping_info {
struct list_head softirq_node; struct list_head softirq_node;
struct msi_info vmsi; struct msi_info vmsi;
struct msi_info pmsi; struct msi_info pmsi;
uint16_t irte_idx;
uint64_t intr_count; uint64_t intr_count;
struct hv_timer intr_delay_timer; /* used for delay intr injection */ struct hv_timer intr_delay_timer; /* used for delay intr injection */