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 <alex.merritt@intel.com>
Reviewed-by: Eddie Dong <eddie.dong@intel.com>
Reviewed-by: Jason Chen CJ <jason.cj.chen@intel.com>
This commit is contained in:
Alexander Merritt 2019-11-01 00:08:28 -07:00 committed by wenlingz
parent 34c75a0b60
commit 94a456ae24

View File

@ -21,6 +21,7 @@
#include <logmsg.h>
#include <board.h>
#include <vm_configurations.h>
#include <pci.h>
#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)