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,6 +71,7 @@ static void ptirq_free_irte(const struct ptirq_remapping_info *entry)
{
struct intr_source intr_src;
if (entry->irte_idx < CONFIG_MAX_IR_ENTRIES) {
if (entry->intr_type == PTDEV_INTR_MSI) {
intr_src.is_msi = true;
intr_src.src.msi.value = entry->phys_sid.msi_id.bdf;
@ -78,8 +79,8 @@ static void ptirq_free_irte(const struct ptirq_remapping_info *entry)
intr_src.is_msi = false;
intr_src.src.ioapic_id = ioapic_irq_to_ioapic_id(entry->allocated_pirq);
}
dmar_free_irte(&intr_src, (uint16_t)entry->allocated_pirq);
dmar_free_irte(&intr_src, entry->irte_idx);
}
}
/*
@ -89,7 +90,7 @@ static void ptirq_free_irte(const struct ptirq_remapping_info *entry)
* that posted mode shall be used
*/
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;
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.pid_paddr = pid_paddr;
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) {
entry->pmsi.data.full = 0U;
entry->pmsi.addr.full = 0UL;
entry->irte_idx = ir_index.index;
if (ir_index.index != INVALID_IRTE_ID) {
/*
* 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.pid_paddr = 0UL;
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) {
entry->irte_idx = ir_index.index;
if (ir_index.index != INVALID_IRTE_ID) {
rte.ir_bits.vector = vector;
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.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",
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.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,
"deactive %s intx entry:pgsi=%d, pirq=%d ",
(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
*/
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;
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
* 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) {
/*
* All the vCPUs are in xAPIC mode and LAPIC is emulated
* 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) {
/*
* 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)) {
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 {
/* 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 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;
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;
}
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,
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));
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 <irq.h>
#include <logmsg.h>
#include <vtd.h>
#define PTIRQ_ENTRY_HASHBITS 9U
#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->vm = vm;
entry->intr_count = 0UL;
entry->irte_idx = INVALID_IRTE_ID;
INIT_LIST_HEAD(&entry->softirq_node);

View File

@ -31,6 +31,7 @@
#include <ptdev.h>
#include <assign.h>
#include <vpci.h>
#include <vtd.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.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);
if (vdev->msi.is_64bit) {
pci_pdev_write_cfg(pbdf, capoff + PCIR_MSI_ADDR_HIGH, 0x4U,

View File

@ -36,6 +36,7 @@
#include <ept.h>
#include <mmu.h>
#include <logmsg.h>
#include <vtd.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.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) {
/* Write the table entry to the physical structure */
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] entry_nr indicate coming vectors, entry_nr = 0 means first vector
* @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
* - 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,
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 msi_info vmsi;
struct msi_info pmsi;
uint16_t irte_idx;
uint64_t intr_count;
struct hv_timer intr_delay_timer; /* used for delay intr injection */