diff --git a/hypervisor/arch/x86/vtd.c b/hypervisor/arch/x86/vtd.c index 67de8eae6..c687eabd7 100644 --- a/hypervisor/arch/x86/vtd.c +++ b/hypervisor/arch/x86/vtd.c @@ -1290,6 +1290,33 @@ static bool is_irte_reserved(const struct dmar_drhd_rt *dmar_unit, uint16_t inde return ((dmar_unit->irte_reserved_bitmap[index >> 6U] & (1UL << (index & 0x3FU))) != 0UL); } +int32_t dmar_reserve_irte(const struct intr_source *intr_src, uint16_t num, uint16_t *start_id) +{ + struct dmar_drhd_rt *dmar_unit; + union pci_bdf sid; + uint64_t mask = (1UL << num) - 1U; + int32_t ret = -EINVAL; + + if (intr_src->is_msi) { + dmar_unit = device_to_dmaru((uint8_t)intr_src->src.msi.bits.b, intr_src->src.msi.fields.devfun); + sid.value = (uint16_t)(intr_src->src.msi.value); + } else { + dmar_unit = ioapic_to_dmaru(intr_src->src.ioapic_id, &sid); + } + + if (is_dmar_unit_valid(dmar_unit, sid)) { + *start_id = alloc_irtes(dmar_unit, num); + if (*start_id < CONFIG_MAX_IR_ENTRIES) { + dmar_unit->irte_reserved_bitmap[*start_id >> 6U] |= mask << (*start_id & 0x3FU); + } + ret = 0; + } + + pr_dbg("%s: for dev 0x%x:%x.%x, reserve %u entry for MSI(%d), start from %d", + __func__, sid.bits.b, sid.bits.d, sid.bits.f, num, intr_src->is_msi, *start_id); + return ret; +} + int32_t dmar_assign_irte(const struct intr_source *intr_src, union dmar_ir_entry *irte, uint16_t idx_in, uint16_t *idx_out) { diff --git a/hypervisor/include/arch/x86/vtd.h b/hypervisor/include/arch/x86/vtd.h index bfd550dd2..90f103393 100644 --- a/hypervisor/include/arch/x86/vtd.h +++ b/hypervisor/include/arch/x86/vtd.h @@ -671,6 +671,21 @@ void resume_iommu(void); */ int32_t init_iommu(void); +/** + * @brief Reserve num continuous IRTEs. + * + * @param[in] intr_src filled with type of interrupt source and the source + * @param[in] num number of IRTEs to reserve + * @param[out] start_id stard index of reserved IRTEs, caller should check the value is INVALID_IRTE_ID or not. + * + * @retval 0 on success, caller should check whether the returned start index is valid or not. + * @retval -EINVAL if corresponding DMAR is not preset. + * + * @pre num can only be 2, 4, 8, 16 or 32 + * + */ +int32_t dmar_reserve_irte(const struct intr_source *intr_src, uint16_t num, uint16_t *start_id); + /** * @brief Assign RTE for Interrupt Remapping Table. *