mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-28 16:27:01 +00:00
hv: Use Interrupt Remapping format for programming interrupt sources
When a corresponding IOMMU is found for the device, this patch adds support to program Interrupt Remapping hardware RTEs and the original interrupt sources (MSI or IOAPIC) with IR format. Tracked-On: #2426 Signed-off-by: Sainath Grandhi <sainath.grandhi@intel.com> Reviewed-by: Binbin Wu <binbin.wu@intel.com>
This commit is contained in:
parent
7104f0a512
commit
970821462b
@ -70,11 +70,15 @@ static uint32_t calculate_logical_dest_mask(uint64_t pdmask)
|
||||
}
|
||||
|
||||
static void ptirq_build_physical_msi(struct acrn_vm *vm, struct ptirq_msi_info *info,
|
||||
uint32_t vector)
|
||||
const struct ptirq_remapping_info *entry, uint32_t vector)
|
||||
{
|
||||
uint64_t vdmask, pdmask;
|
||||
uint32_t dest, delmode, dest_mask;
|
||||
bool phys;
|
||||
union dmar_ir_entry irte;
|
||||
union irte_index ir_index;
|
||||
int32_t ret;
|
||||
struct intr_source intr_src;
|
||||
|
||||
/* get physical destination cpu mask */
|
||||
dest = info->vmsi_addr.bits.dest_field;
|
||||
@ -89,19 +93,51 @@ static void ptirq_build_physical_msi(struct acrn_vm *vm, struct ptirq_msi_info *
|
||||
delmode = MSI_DATA_DELMODE_LOPRI;
|
||||
}
|
||||
|
||||
/* update physical delivery mode & vector */
|
||||
dest_mask = calculate_logical_dest_mask(pdmask);
|
||||
|
||||
/* Using phys_irq as index in the corresponding IOMMU */
|
||||
irte.entry.lower = 0UL;
|
||||
irte.entry.upper = 0UL;
|
||||
irte.bits.vector = vector;
|
||||
irte.bits.delivery_mode = delmode;
|
||||
irte.bits.dest_mode = MSI_ADDR_DESTMODE_LOGICAL;
|
||||
irte.bits.rh = MSI_ADDR_RH;
|
||||
irte.bits.dest = dest_mask;
|
||||
|
||||
intr_src.is_msi = true;
|
||||
intr_src.src.msi.value = entry->phys_sid.msi_id.bdf;
|
||||
ret = dmar_assign_irte(intr_src, irte, (uint16_t)entry->allocated_pirq);
|
||||
|
||||
if (ret == 0) {
|
||||
/*
|
||||
* Update the MSI interrupt source to point to the IRTE
|
||||
* SHV is set to 0 as ACRN disables MMC (Multi-Message Capable
|
||||
* for MSI devices.
|
||||
*/
|
||||
info->pmsi_data.full = 0U;
|
||||
ir_index.index = (uint16_t)entry->allocated_pirq;
|
||||
|
||||
info->pmsi_addr.full = 0UL;
|
||||
info->pmsi_addr.ir_bits.intr_index_high = ir_index.bits.index_high;
|
||||
info->pmsi_addr.ir_bits.shv = 0U;
|
||||
info->pmsi_addr.ir_bits.intr_format = 0x1U;
|
||||
info->pmsi_addr.ir_bits.intr_index_low = ir_index.bits.index_low;
|
||||
info->pmsi_addr.ir_bits.constant = 0xFEEU;
|
||||
} else {
|
||||
/* In case there is no corresponding IOMMU, for example, if the
|
||||
* IOMMU is ignored, pass the MSI info in Compatibility Format
|
||||
*/
|
||||
info->pmsi_data = info->vmsi_data;
|
||||
info->pmsi_data.bits.delivery_mode = delmode;
|
||||
info->pmsi_data.bits.vector = vector;
|
||||
|
||||
dest_mask = calculate_logical_dest_mask(pdmask);
|
||||
/* update physical dest mode & dest field */
|
||||
info->pmsi_addr = info->vmsi_addr;
|
||||
info->pmsi_addr.bits.dest_mode = MSI_ADDR_DESTMODE_LOGICAL;
|
||||
info->pmsi_addr.bits.rh = MSI_ADDR_RH;
|
||||
info->pmsi_addr.bits.dest_field = dest_mask;
|
||||
|
||||
dev_dbg(ACRN_DBG_IRQ, "MSI addr:data = 0x%llx:%x(V) -> 0x%llx:%x(P)",
|
||||
info->pmsi_addr.bits.rh = MSI_ADDR_RH;
|
||||
info->pmsi_addr.bits.dest_mode = MSI_ADDR_DESTMODE_LOGICAL;
|
||||
}
|
||||
dev_dbg(ACRN_DBG_IRQ, "MSI %s addr:data = 0x%llx:%x(V) -> 0x%llx:%x(P)",
|
||||
(info->pmsi_addr.ir_bits.intr_format != 0U) ? " Remappable Format" : "Compatibility Format",
|
||||
info->vmsi_addr.full, info->vmsi_data.full,
|
||||
info->pmsi_addr.full, info->pmsi_data.full);
|
||||
}
|
||||
@ -112,6 +148,10 @@ ptirq_build_physical_rte(struct acrn_vm *vm, struct ptirq_remapping_info *entry)
|
||||
union ioapic_rte rte;
|
||||
uint32_t phys_irq = entry->allocated_pirq;
|
||||
union source_id *virt_sid = &entry->virt_sid;
|
||||
union irte_index ir_index;
|
||||
union dmar_ir_entry irte;
|
||||
struct intr_source intr_src;
|
||||
int32_t ret;
|
||||
|
||||
if (virt_sid->intx_id.src == PTDEV_VPIN_IOAPIC) {
|
||||
uint64_t vdmask, pdmask;
|
||||
@ -150,15 +190,36 @@ ptirq_build_physical_rte(struct acrn_vm *vm, struct ptirq_remapping_info *entry)
|
||||
|
||||
/* update physical delivery mode, dest mode(logical) & vector */
|
||||
vector = irq_to_vector(phys_irq);
|
||||
dest_mask = calculate_logical_dest_mask(pdmask);
|
||||
|
||||
irte.entry.lower = 0UL;
|
||||
irte.entry.upper = 0UL;
|
||||
irte.bits.vector = vector;
|
||||
irte.bits.delivery_mode = delmode;
|
||||
irte.bits.dest_mode = IOAPIC_RTE_DESTMODE_LOGICAL;
|
||||
irte.bits.dest = dest_mask;
|
||||
irte.bits.trigger_mode = rte.bits.trigger_mode;
|
||||
|
||||
intr_src.is_msi = false;
|
||||
intr_src.src.ioapic_id = ioapic_irq_to_ioapic_id(phys_irq);
|
||||
ret = dmar_assign_irte(intr_src, irte, (uint16_t)phys_irq);
|
||||
|
||||
if (ret == 0) {
|
||||
ir_index.index = (uint16_t)phys_irq;
|
||||
rte.ir_bits.vector = vector;
|
||||
rte.ir_bits.constant = 0U;
|
||||
rte.ir_bits.intr_index_high = ir_index.bits.index_high;
|
||||
rte.ir_bits.intr_format = 1U;
|
||||
rte.ir_bits.intr_index_low = ir_index.bits.index_low;
|
||||
} else {
|
||||
rte.bits.dest_mode = IOAPIC_RTE_DESTMODE_LOGICAL;
|
||||
rte.bits.delivery_mode = delmode;
|
||||
rte.bits.vector = vector;
|
||||
|
||||
dest_mask = calculate_logical_dest_mask(pdmask);
|
||||
/* update physical dest field */
|
||||
rte.bits.dest_field = dest_mask;
|
||||
}
|
||||
|
||||
dev_dbg(ACRN_DBG_IRQ, "IOAPIC RTE = 0x%x:%x(V) -> 0x%x:%x(P)",
|
||||
dev_dbg(ACRN_DBG_IRQ, "IOAPIC RTE %s = 0x%x:%x(V) -> 0x%x:%x(P)",
|
||||
(rte.ir_bits.intr_format != 0U) ? "Remappable Format" : "Compatibility Format",
|
||||
virt_rte.u.hi_32, virt_rte.u.lo_32,
|
||||
rte.u.hi_32, rte.u.lo_32);
|
||||
} else {
|
||||
@ -174,7 +235,8 @@ ptirq_build_physical_rte(struct acrn_vm *vm, struct ptirq_remapping_info *entry)
|
||||
rte.bits.trigger_mode = IOAPIC_RTE_TRGRMODE_LEVEL;
|
||||
}
|
||||
|
||||
dev_dbg(ACRN_DBG_IRQ, "IOAPIC RTE = 0x%x:%x(P) -> 0x%x:%x(P)",
|
||||
dev_dbg(ACRN_DBG_IRQ, "IOAPIC RTE %s = 0x%x:%x(P) -> 0x%x:%x(P)",
|
||||
(rte.ir_bits.intr_format != 0U) ? "Remappable Format" : "Compatibility Format",
|
||||
phys_rte.u.hi_32, phys_rte.u.lo_32,
|
||||
rte.u.hi_32, rte.u.lo_32);
|
||||
}
|
||||
@ -239,6 +301,7 @@ remove_msix_remapping(const struct acrn_vm *vm, uint16_t virt_bdf, uint32_t entr
|
||||
{
|
||||
struct ptirq_remapping_info *entry;
|
||||
DEFINE_MSI_SID(virt_sid, virt_bdf, entry_nr);
|
||||
struct intr_source intr_src;
|
||||
|
||||
entry = ptirq_lookup_entry_by_sid(PTDEV_INTR_MSI, &virt_sid, vm);
|
||||
if (entry != NULL) {
|
||||
@ -247,6 +310,10 @@ remove_msix_remapping(const struct acrn_vm *vm, uint16_t virt_bdf, uint32_t entr
|
||||
ptirq_deactivate_entry(entry);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
dev_dbg(ACRN_DBG_IRQ,
|
||||
"VM%d MSIX remove vector mapping vbdf-pbdf:0x%x-0x%x idx=%d",
|
||||
entry->vm->vm_id, virt_bdf,
|
||||
@ -326,6 +393,7 @@ static void remove_intx_remapping(struct acrn_vm *vm, uint32_t virt_pin, bool pi
|
||||
{
|
||||
uint32_t phys_irq;
|
||||
struct ptirq_remapping_info *entry;
|
||||
struct intr_source intr_src;
|
||||
|
||||
if (((!pic_pin) && (virt_pin >= vioapic_pincount(vm))) || (pic_pin && (virt_pin >= vpic_pincount()))) {
|
||||
pr_err("virtual irq pin is invalid!\n");
|
||||
@ -338,6 +406,10 @@ static void remove_intx_remapping(struct acrn_vm *vm, uint32_t virt_pin, bool pi
|
||||
ioapic_gsi_mask_irq(phys_irq);
|
||||
|
||||
ptirq_deactivate_entry(entry);
|
||||
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);
|
||||
dev_dbg(ACRN_DBG_IRQ,
|
||||
"deactive %s intx entry:ppin=%d, pirq=%d ",
|
||||
pic_pin ? "vPIC" : "vIOAPIC",
|
||||
@ -543,9 +615,9 @@ int32_t ptirq_msix_remap(struct acrn_vm *vm, uint16_t virt_bdf,
|
||||
/* build physical config MSI, update to info->pmsi_xxx */
|
||||
if (is_lapic_pt(vm)) {
|
||||
/* for vm with lapic-pt, keep vector from guest */
|
||||
ptirq_build_physical_msi(vm, info, info->vmsi_data.bits.vector);
|
||||
ptirq_build_physical_msi(vm, info, entry, (uint32_t)info->vmsi_data.bits.vector);
|
||||
} else {
|
||||
ptirq_build_physical_msi(vm, info, irq_to_vector(entry->allocated_pirq));
|
||||
ptirq_build_physical_msi(vm, info, entry, irq_to_vector(entry->allocated_pirq));
|
||||
}
|
||||
|
||||
entry->msi = *info;
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <acpi.h>
|
||||
|
||||
#define IOAPIC_MAX_PIN 240U
|
||||
#define IOAPIC_INVALID_ID 0xFFU
|
||||
|
||||
/*
|
||||
* IOAPIC_MAX_LINES is architecturally defined.
|
||||
@ -370,6 +371,19 @@ ioapic_nr_pins(void *ioapic_base)
|
||||
return nr_pins;
|
||||
}
|
||||
|
||||
uint8_t ioapic_irq_to_ioapic_id(uint32_t irq)
|
||||
{
|
||||
uint8_t ret;
|
||||
|
||||
if (ioapic_irq_is_gsi(irq)) {
|
||||
ret = gsi_table_data[irq].ioapic_id;
|
||||
} else {
|
||||
ret = IOAPIC_INVALID_ID;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t init_ioapic_id_info(void)
|
||||
{
|
||||
int32_t ret = 0;
|
||||
|
@ -76,6 +76,7 @@ static inline uint64_t dmar_set_bitslice(uint64_t var, uint64_t mask, uint32_t p
|
||||
#define DMAR_INV_STATUS_WRITE_SHIFT 5U
|
||||
#define DMAR_INV_CONTEXT_CACHE_DESC 0x01UL
|
||||
#define DMAR_INV_IOTLB_DESC 0x02UL
|
||||
#define DMAR_INV_IEC_DESC 0x04UL
|
||||
#define DMAR_INV_WAIT_DESC 0x05UL
|
||||
#define DMAR_INV_STATUS_WRITE (1UL << DMAR_INV_STATUS_WRITE_SHIFT)
|
||||
#define DMAR_INV_STATUS_INCOMPLETE 0UL
|
||||
@ -87,6 +88,9 @@ static inline uint64_t dmar_set_bitslice(uint64_t var, uint64_t mask, uint32_t p
|
||||
#define DMAR_IR_ENABLE_EIM_SHIFT 11UL
|
||||
#define DMAR_IR_ENABLE_EIM (1UL << DMAR_IR_ENABLE_EIM_SHIFT)
|
||||
|
||||
#define DMAR_IECI_INDEXED 1U
|
||||
#define DMAR_IEC_GLOBAL_INVL 0U
|
||||
|
||||
enum dmar_cirg_type {
|
||||
DMAR_CIRG_RESERVED = 0,
|
||||
DMAR_CIRG_GLOBAL,
|
||||
@ -503,6 +507,41 @@ static int32_t dmar_register_hrhd(struct dmar_drhd_rt *dmar_unit)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct dmar_drhd_rt *ioapic_to_dmaru(uint16_t ioapic_id, union pci_bdf *sid)
|
||||
{
|
||||
struct dmar_info *info = get_dmar_info();
|
||||
struct dmar_drhd_rt *dmar_unit = NULL;
|
||||
uint32_t i, j;
|
||||
bool found = false;
|
||||
|
||||
if (info == NULL) {
|
||||
pr_fatal("%s: can't find dmar info\n", __func__);
|
||||
} else {
|
||||
for (j = 0U; j < info->drhd_count; j++) {
|
||||
dmar_unit = &dmar_drhd_units[j];
|
||||
for (i = 0U; i < dmar_unit->drhd->dev_cnt; i++) {
|
||||
if ((dmar_unit->drhd->devices[i].type == ACPI_DMAR_SCOPE_TYPE_IOAPIC) &&
|
||||
(dmar_unit->drhd->devices[i].id == ioapic_id)) {
|
||||
sid->bits.f = pci_func((uint8_t)dmar_unit->drhd->devices[i].devfun);
|
||||
sid->bits.d = pci_slot((uint8_t)dmar_unit->drhd->devices[i].devfun);
|
||||
sid->bits.b = dmar_unit->drhd->devices[i].bus;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j == info->drhd_count) {
|
||||
dmar_unit = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return dmar_unit;
|
||||
}
|
||||
|
||||
static struct dmar_drhd_rt *device_to_dmaru(uint16_t segment, uint8_t bus, uint8_t devfun)
|
||||
{
|
||||
struct dmar_info *info = get_dmar_info();
|
||||
@ -695,6 +734,34 @@ static void dmar_set_intr_remap_table(struct dmar_drhd_rt *dmar_unit)
|
||||
spinlock_release(&(dmar_unit->lock));
|
||||
}
|
||||
|
||||
static void dmar_invalid_iec(struct dmar_drhd_rt *dmar_unit, uint16_t intr_index,
|
||||
uint8_t index_mask, bool is_global)
|
||||
{
|
||||
struct dmar_qi_desc invalidate_desc;
|
||||
|
||||
invalidate_desc.upper = 0UL;
|
||||
invalidate_desc.lower = DMAR_INV_IEC_DESC;
|
||||
|
||||
if (is_global) {
|
||||
invalidate_desc.lower |= DMAR_IEC_GLOBAL_INVL;
|
||||
} else {
|
||||
invalidate_desc.lower |= DMAR_IECI_INDEXED | dma_iec_index(intr_index, index_mask);
|
||||
}
|
||||
|
||||
if (invalidate_desc.lower != 0UL) {
|
||||
spinlock_obtain(&(dmar_unit->lock));
|
||||
|
||||
dmar_issue_qi_request(dmar_unit, invalidate_desc);
|
||||
|
||||
spinlock_release(&(dmar_unit->lock));
|
||||
}
|
||||
}
|
||||
|
||||
static void dmar_invalid_iec_global(struct dmar_drhd_rt *dmar_unit)
|
||||
{
|
||||
dmar_invalid_iec(dmar_unit, 0U, 0U, true);
|
||||
}
|
||||
|
||||
static void dmar_set_root_table(struct dmar_drhd_rt *dmar_unit)
|
||||
{
|
||||
uint64_t address;
|
||||
@ -1280,3 +1347,78 @@ void init_iommu_sos_vm_domain(struct acrn_vm *sos_vm)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t dmar_assign_irte(struct intr_source intr_src, union dmar_ir_entry irte, uint16_t index)
|
||||
{
|
||||
struct dmar_drhd_rt *dmar_unit;
|
||||
union dmar_ir_entry *ir_table, *ir_entry;
|
||||
union pci_bdf sid;
|
||||
uint64_t trigger_mode;
|
||||
int32_t ret = 0;
|
||||
|
||||
if (intr_src.is_msi) {
|
||||
dmar_unit = device_to_dmaru(0U, (uint8_t)intr_src.src.msi.bits.b, pci_devfn(intr_src.src.msi.value));
|
||||
sid.value = intr_src.src.msi.value;
|
||||
trigger_mode = 0x0UL;
|
||||
} else {
|
||||
dmar_unit = ioapic_to_dmaru(intr_src.src.ioapic_id, &sid);
|
||||
trigger_mode = irte.bits.trigger_mode;
|
||||
}
|
||||
|
||||
if (dmar_unit == NULL) {
|
||||
pr_err("no dmar unit found for device: %x:%x.%x", sid.bits.b, sid.bits.d, sid.bits.f);
|
||||
ret = -EINVAL;
|
||||
} else if (dmar_unit->drhd->ignore) {
|
||||
dev_dbg(ACRN_DBG_IOMMU, "device is ignored :0x%x:%x.%x", sid.bits.b, sid.bits.d, sid.bits.f);
|
||||
ret = -EINVAL;
|
||||
} else if (dmar_unit->ir_table_addr == 0UL) {
|
||||
pr_err("IR table is not set for dmar unit");
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
irte.bits.svt = 0x1UL;
|
||||
irte.bits.sq = 0x0UL;
|
||||
irte.bits.sid = sid.value;
|
||||
irte.bits.present = 0x1UL;
|
||||
irte.bits.mode = 0x0UL;
|
||||
irte.bits.trigger_mode = trigger_mode;
|
||||
irte.bits.fpd = 0x0UL;
|
||||
ir_table = (union dmar_ir_entry *)hpa2hva(dmar_unit->ir_table_addr);
|
||||
ir_entry = ir_table + index;
|
||||
ir_entry->entry.upper = irte.entry.upper;
|
||||
ir_entry->entry.lower = irte.entry.lower;
|
||||
|
||||
iommu_flush_cache(dmar_unit, ir_entry, sizeof(union dmar_ir_entry));
|
||||
dmar_invalid_iec_global(dmar_unit);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dmar_free_irte(struct intr_source intr_src, uint16_t index)
|
||||
{
|
||||
struct dmar_drhd_rt *dmar_unit;
|
||||
union dmar_ir_entry *ir_table, *ir_entry;
|
||||
union pci_bdf sid;
|
||||
|
||||
if (intr_src.is_msi) {
|
||||
dmar_unit = device_to_dmaru(0U, (uint8_t)intr_src.src.msi.bits.b, pci_devfn(intr_src.src.msi.value));
|
||||
} else {
|
||||
dmar_unit = ioapic_to_dmaru(intr_src.src.ioapic_id, &sid);
|
||||
}
|
||||
|
||||
if (dmar_unit == NULL) {
|
||||
pr_err("no dmar unit found for device: %x:%x.%x", intr_src.src.msi.bits.b,
|
||||
intr_src.src.msi.bits.d, intr_src.src.msi.bits.f);
|
||||
} else if (dmar_unit->drhd->ignore) {
|
||||
dev_dbg(ACRN_DBG_IOMMU, "device is ignored :0x%x:%x.%x", intr_src.src.msi.bits.b,
|
||||
intr_src.src.msi.bits.d, intr_src.src.msi.bits.f);
|
||||
} else if (dmar_unit->ir_table_addr == 0UL) {
|
||||
pr_err("IR table is not set for dmar unit");
|
||||
} else {
|
||||
ir_table = (union dmar_ir_entry *)hpa2hva(dmar_unit->ir_table_addr);
|
||||
ir_entry = ir_table + index;
|
||||
ir_entry->bits.present = 0x0UL;
|
||||
|
||||
iommu_flush_cache(dmar_unit, ir_entry, sizeof(union dmar_ir_entry));
|
||||
dmar_invalid_iec_global(dmar_unit);
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ enum acpi_dmar_type {
|
||||
ACPI_DMAR_TYPE_RESERVED = 5
|
||||
};
|
||||
|
||||
|
||||
struct acpi_table_dmar {
|
||||
/* Common ACPI table header */
|
||||
struct acpi_table_header header;
|
||||
|
@ -209,6 +209,19 @@ union ioapic_rte {
|
||||
uint64_t rsvd_1:39;
|
||||
uint64_t dest_field:8;
|
||||
} bits __packed;
|
||||
struct {
|
||||
uint32_t vector:8;
|
||||
uint32_t constant:3;
|
||||
uint32_t intr_index_high:1;
|
||||
uint32_t intr_polarity:1;
|
||||
uint32_t remote_irr:1;
|
||||
uint32_t trigger_mode:1;
|
||||
uint32_t intr_mask:1;
|
||||
uint32_t rsvd_1:15;
|
||||
uint32_t rsvd_2:16;
|
||||
uint32_t intr_format:1;
|
||||
uint32_t intr_index_low:15;
|
||||
} ir_bits __packed;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -21,6 +21,7 @@ void ioapic_setup_irqs(void);
|
||||
bool ioapic_irq_is_gsi(uint32_t irq);
|
||||
uint32_t ioapic_irq_to_pin(uint32_t irq);
|
||||
int32_t init_ioapic_id_info(void);
|
||||
uint8_t ioapic_irq_to_ioapic_id(uint32_t irq);
|
||||
|
||||
/**
|
||||
* @brief Get irq num from pin num
|
||||
|
@ -347,6 +347,11 @@ static inline uint8_t dma_iotlb_invl_addr_am(uint8_t am)
|
||||
return (am & 0x3fU);
|
||||
}
|
||||
|
||||
static inline uint64_t dma_iec_index(uint16_t index, uint8_t index_mask)
|
||||
{
|
||||
return ((((uint64_t)index & 0xFFFFU) << 32U) | (((uint64_t)index_mask & 0x1FU) << 27U));
|
||||
}
|
||||
|
||||
#define DMA_IOTLB_INVL_ADDR_IH_UNMODIFIED (((uint64_t)1UL) << 6U)
|
||||
|
||||
/* FECTL_REG */
|
||||
@ -474,6 +479,31 @@ struct dmar_info {
|
||||
struct dmar_drhd *drhd_units;
|
||||
};
|
||||
|
||||
union dmar_ir_entry {
|
||||
struct {
|
||||
uint64_t lower;
|
||||
uint64_t upper;
|
||||
} entry;
|
||||
struct {
|
||||
uint64_t present:1;
|
||||
uint64_t fpd:1;
|
||||
uint64_t dest_mode:1;
|
||||
uint64_t rh:1;
|
||||
uint64_t trigger_mode:1;
|
||||
uint64_t delivery_mode:3;
|
||||
uint64_t sw_bits:4;
|
||||
uint64_t rsvd_1:3;
|
||||
uint64_t mode:1;
|
||||
uint64_t vector:8;
|
||||
uint64_t rsvd_2:8;
|
||||
uint64_t dest:32;
|
||||
uint64_t sid:16;
|
||||
uint64_t sq:2;
|
||||
uint64_t svt:2;
|
||||
uint64_t rsvd_3:44;
|
||||
} bits __packed;
|
||||
};
|
||||
|
||||
extern struct dmar_info *get_dmar_info(void);
|
||||
|
||||
/**
|
||||
@ -635,6 +665,27 @@ void init_iommu_sos_vm_domain(struct acrn_vm *sos_vm);
|
||||
*/
|
||||
bool iommu_snoop_supported(const struct acrn_vm *vm);
|
||||
|
||||
/**
|
||||
* @brief Assign RTE for Interrupt Remapping Table.
|
||||
*
|
||||
* @param[in] intr_src filled with type of interrupt source and the source
|
||||
* @param[in] irte filled with info about interrupt deliverymode, destination and destination mode
|
||||
* @param[in] index into Interrupt Remapping Table
|
||||
*
|
||||
* @retval -EINVAL if corresponding DMAR is not present
|
||||
* @retval 0 otherwise
|
||||
*
|
||||
*/
|
||||
int32_t dmar_assign_irte(struct intr_source intr_src, union dmar_ir_entry irte, uint16_t index);
|
||||
|
||||
/**
|
||||
* @brief Free RTE for Interrupt Remapping Table.
|
||||
*
|
||||
* @param[in] intr_src filled with type of interrupt source and the source
|
||||
* @param[in] index into Interrupt Remapping Table
|
||||
*
|
||||
*/
|
||||
void dmar_free_irte(struct intr_source intr_src, uint16_t index);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
@ -23,6 +23,24 @@ union source_id (name) = {.msi_id = {.bdf = (a), .entry_nr = (b)} }
|
||||
#define DEFINE_IOAPIC_SID(name, a, b) \
|
||||
union source_id (name) = {.intx_id = {.pin = (a), .src = (b)} }
|
||||
|
||||
union source {
|
||||
uint16_t ioapic_id;
|
||||
union pci_bdf msi;
|
||||
};
|
||||
|
||||
struct intr_source {
|
||||
bool is_msi;
|
||||
union source src;
|
||||
};
|
||||
|
||||
union irte_index {
|
||||
uint16_t index;
|
||||
struct {
|
||||
uint16_t index_low:15;
|
||||
uint16_t index_high:1;
|
||||
} bits __packed;
|
||||
};
|
||||
|
||||
union source_id {
|
||||
uint64_t value;
|
||||
struct {
|
||||
@ -56,6 +74,16 @@ union msi_addr_reg {
|
||||
uint32_t addr_base:12;
|
||||
uint32_t hi_32;
|
||||
} bits __packed;
|
||||
struct {
|
||||
uint32_t rsvd_1:2;
|
||||
uint32_t intr_index_high:1;
|
||||
uint32_t shv:1;
|
||||
uint32_t intr_format:1;
|
||||
uint32_t intr_index_low:15;
|
||||
uint32_t constant:12;
|
||||
uint32_t hi_32;
|
||||
} ir_bits __packed;
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -174,6 +174,11 @@ static inline uint8_t pci_func(uint16_t bdf)
|
||||
return (uint8_t)(bdf & 0x7U);
|
||||
}
|
||||
|
||||
static inline uint8_t pci_devfn(uint16_t bdf)
|
||||
{
|
||||
return (uint8_t)(bdf & 0xFFU);
|
||||
}
|
||||
|
||||
uint32_t pci_pdev_read_cfg(union pci_bdf bdf, uint32_t offset, uint32_t bytes);
|
||||
void pci_pdev_write_cfg(union pci_bdf bdf, uint32_t offset, uint32_t bytes, uint32_t val);
|
||||
void enable_disable_pci_intx(union pci_bdf bdf, bool enable);
|
||||
|
Loading…
Reference in New Issue
Block a user