From 94a456ae24073545bf19f685cb6f36117ec497f5 Mon Sep 17 00:00:00 2001 From: Alexander Merritt Date: Fri, 1 Nov 2019 00:08:28 -0700 Subject: [PATCH] HV: refactor device_to_dmaru On server platforms, DMAR DRHD device scope entries may contain PCI bridges. Bridges in the DRHD device scope indicate this IOMMU translates for all devices on the hierarchy below that bridge. ACRN is unaware of bridge types in the device scope, and adds these directly to its internal representation of a DRHD. When looking up a BDF within these DRHD entries, device_to_dmaru assumes all entries are Endpoints, comparing BDF to BDF. Thus device to DMAR unit fails, because it treats a bridge as an Endpoint type. This change leverages prior patches by converting a BDF to the associated device DRHD index, and uses that index to obtain the correct DRHD state. Handling a bridge in other ways may require maintaining a bus list for each, or replacing each bridge in the dev scope with a set of all device BDFs underneath it. Server platforms can have hundreds of PCI devices, thus making the device scope artificially large is unwieldy. Tracked-On: #4134 Signed-off-by: Alexander Merritt Reviewed-by: Eddie Dong Reviewed-by: Jason Chen CJ --- hypervisor/arch/x86/vtd.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/hypervisor/arch/x86/vtd.c b/hypervisor/arch/x86/vtd.c index a6dffe509..3f8c7ea57 100644 --- a/hypervisor/arch/x86/vtd.c +++ b/hypervisor/arch/x86/vtd.c @@ -21,6 +21,7 @@ #include #include #include +#include #define DBG_IOMMU 0 @@ -555,30 +556,23 @@ static struct dmar_drhd_rt *ioapic_to_dmaru(uint16_t ioapic_id, union pci_bdf *s static struct dmar_drhd_rt *device_to_dmaru(uint8_t bus, uint8_t devfun) { - struct dmar_drhd_rt *dmar_unit = NULL; - uint32_t i, j; + struct dmar_drhd_rt *dmaru = NULL; + uint16_t bdf = ((uint16_t)bus << 8U) | devfun; + uint32_t index = pci_lookup_drhd_for_pbdf(bdf); - for (j = 0U; j < platform_dmar_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].bus == bus) && - (dmar_unit->drhd->devices[i].devfun == devfun)) { - break; - } - } - - if ((i != dmar_unit->drhd->dev_cnt) || ((dmar_unit->drhd->flags & DRHD_FLAG_INCLUDE_PCI_ALL_MASK) != 0U)) { - break; - } + if (index == INVALID_DRHD_INDEX) { + pr_fatal("BDF %02x:%02x:%x has no IOMMU\n", bus, devfun >> 3U, devfun & 7U); + /* + * pci_lookup_drhd_for_pbdf would return -1U for any of the reasons + * 1) PCI device with bus, devfun does not exist on platform + * 2) ACRN had issues finding the device with bus, devfun during init + * 3) DMAR tables provided by ACPI for this platform are incorrect + */ + } else { + dmaru = &dmar_drhd_units[index]; } - /* not found */ - if (j == platform_dmar_info->drhd_count) { - dmar_unit = NULL; - } - - return dmar_unit; + return dmaru; } static void dmar_issue_qi_request(struct dmar_drhd_rt *dmar_unit, struct dmar_entry invalidate_desc)