diff --git a/hypervisor/arch/x86/guest/assign.c b/hypervisor/arch/x86/guest/assign.c index 741ae966f..a73856d60 100644 --- a/hypervisor/arch/x86/guest/assign.c +++ b/hypervisor/arch/x86/guest/assign.c @@ -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 */ - 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)", + /* 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; + + info->pmsi_addr = info->vmsi_addr; + info->pmsi_addr.bits.dest_field = dest_mask; + 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); - 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)", + 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; + rte.bits.dest_field = dest_mask; + } + + 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", @@ -450,8 +522,8 @@ void ptirq_softirq(uint16_t pcpu_id) msi->vmsi_data.bits.vector, irq_to_vector(entry->allocated_pirq)); dev_dbg(ACRN_DBG_PTIRQ, " vmsi_addr: 0x%llx vmsi_data: 0x%x", - msi->vmsi_addr.full, - msi->vmsi_data.full); + msi->vmsi_addr.full, + msi->vmsi_data.full); } } } @@ -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; diff --git a/hypervisor/arch/x86/ioapic.c b/hypervisor/arch/x86/ioapic.c index 1e1924a01..b8a5b9a92 100644 --- a/hypervisor/arch/x86/ioapic.c +++ b/hypervisor/arch/x86/ioapic.c @@ -9,6 +9,7 @@ #include #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; diff --git a/hypervisor/arch/x86/vtd.c b/hypervisor/arch/x86/vtd.c index c81d32b96..2d7d23d51 100644 --- a/hypervisor/arch/x86/vtd.c +++ b/hypervisor/arch/x86/vtd.c @@ -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); + } +} diff --git a/hypervisor/boot/dmar_parse.c b/hypervisor/boot/dmar_parse.c index 7da0410c1..26f225406 100644 --- a/hypervisor/boot/dmar_parse.c +++ b/hypervisor/boot/dmar_parse.c @@ -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; diff --git a/hypervisor/include/arch/x86/apicreg.h b/hypervisor/include/arch/x86/apicreg.h index 27e5e57e7..3e5918dd4 100644 --- a/hypervisor/include/arch/x86/apicreg.h +++ b/hypervisor/include/arch/x86/apicreg.h @@ -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; }; /****************************************************************************** diff --git a/hypervisor/include/arch/x86/ioapic.h b/hypervisor/include/arch/x86/ioapic.h index 661bcbd35..dc8493dfd 100644 --- a/hypervisor/include/arch/x86/ioapic.h +++ b/hypervisor/include/arch/x86/ioapic.h @@ -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 diff --git a/hypervisor/include/arch/x86/vtd.h b/hypervisor/include/arch/x86/vtd.h index 7dd244bf8..3f5828198 100644 --- a/hypervisor/include/arch/x86/vtd.h +++ b/hypervisor/include/arch/x86/vtd.h @@ -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); /** * @} */ diff --git a/hypervisor/include/common/ptdev.h b/hypervisor/include/common/ptdev.h index 3a303fd90..86778c560 100644 --- a/hypervisor/include/common/ptdev.h +++ b/hypervisor/include/common/ptdev.h @@ -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; + }; /* diff --git a/hypervisor/include/dm/pci.h b/hypervisor/include/dm/pci.h index 23d33f9b7..cf6f66e38 100644 --- a/hypervisor/include/dm/pci.h +++ b/hypervisor/include/dm/pci.h @@ -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);