[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen staging] VT-d: Tylersburg isoch DMAR unit with no TLB space
commit d3b05f9b16d6ba9c550c3a35ac11ed292bf87f68 Author: Jan Beulich <jbeulich@xxxxxxxx> AuthorDate: Tue Oct 12 11:57:08 2021 +0200 Commit: Jan Beulich <jbeulich@xxxxxxxx> CommitDate: Tue Oct 12 11:57:08 2021 +0200 VT-d: Tylersburg isoch DMAR unit with no TLB space BIOSes, when enabling the dedicated DMAR unit for the sound device, need to also set a non-zero number of TLB entries in a respective system management register (VTISOCHCTRL). At least one BIOS is known to fail to do so, causing the VT-d engine to deadlock when used. Vaguely based on Linux'es e0fc7e0b4b5e ("intel-iommu: Yet another BIOS workaround: Isoch DMAR unit with no TLB space"). To limit message string redundancy, fold parts with the IGD quirk logic. Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx> Reviewed-by: Kevin Tian <kevin.tian@xxxxxxxxx> Release-Acked-by: Ian Jackson <iwj@xxxxxxxxxxxxxx> --- xen/drivers/passthrough/vtd/extern.h | 1 + xen/drivers/passthrough/vtd/iommu.c | 26 ++++++++++++--- xen/drivers/passthrough/vtd/quirks.c | 63 ++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 5 deletions(-) diff --git a/xen/drivers/passthrough/vtd/extern.h b/xen/drivers/passthrough/vtd/extern.h index 156177bb3f..6fb00a25c3 100644 --- a/xen/drivers/passthrough/vtd/extern.h +++ b/xen/drivers/passthrough/vtd/extern.h @@ -100,6 +100,7 @@ int msi_msg_write_remap_rte(struct msi_desc *, struct msi_msg *); int intel_setup_hpet_msi(struct msi_desc *); int is_igd_vt_enabled_quirk(void); +bool is_azalia_tlb_enabled(const struct acpi_drhd_unit *); void platform_quirks_init(void); void vtd_ops_preamble_quirk(struct vtd_iommu *iommu); void vtd_ops_postamble_quirk(struct vtd_iommu *iommu); diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c index 137aea2c92..0e7e111286 100644 --- a/xen/drivers/passthrough/vtd/iommu.c +++ b/xen/drivers/passthrough/vtd/iommu.c @@ -750,27 +750,43 @@ static void iommu_enable_translation(struct acpi_drhd_unit *drhd) u32 sts; unsigned long flags; struct vtd_iommu *iommu = drhd->iommu; + static const char crash_fmt[] = "%s; crash Xen for security purpose\n"; if ( drhd->gfx_only ) { + static const char disable_fmt[] = XENLOG_WARNING VTDPREFIX + " %s; disabling IGD VT-d engine\n"; + if ( !iommu_igfx ) { - printk(XENLOG_INFO VTDPREFIX - "Passed iommu=no-igfx option. Disabling IGD VT-d engine.\n"); + printk(disable_fmt, "passed iommu=no-igfx option"); return; } if ( !is_igd_vt_enabled_quirk() ) { + static const char msg[] = "firmware did not enable IGD for VT properly"; + if ( force_iommu ) - panic("BIOS did not enable IGD for VT properly, crash Xen for security purpose\n"); + panic(crash_fmt, msg); - printk(XENLOG_WARNING VTDPREFIX - "BIOS did not enable IGD for VT properly. Disabling IGD VT-d engine.\n"); + printk(disable_fmt, msg); return; } } + if ( !is_azalia_tlb_enabled(drhd) ) + { + static const char msg[] = "firmware did not enable TLB for sound device"; + + if ( force_iommu ) + panic(crash_fmt, msg); + + printk(XENLOG_WARNING VTDPREFIX " %s; disabling ISOCH VT-d engine\n", + msg); + return; + } + /* apply platform specific errata workarounds */ vtd_ops_preamble_quirk(iommu); diff --git a/xen/drivers/passthrough/vtd/quirks.c b/xen/drivers/passthrough/vtd/quirks.c index 2ad76a0ae7..52b47dd893 100644 --- a/xen/drivers/passthrough/vtd/quirks.c +++ b/xen/drivers/passthrough/vtd/quirks.c @@ -100,6 +100,69 @@ static void __init cantiga_b3_errata_init(void) is_cantiga_b3 = 1; } +/* + * QUIRK to work around certain BIOSes enabling the ISOCH DMAR unit for the + * Azalia sound device, but not giving it any TLB entries, causing it to + * deadlock. + */ +bool is_azalia_tlb_enabled(const struct acpi_drhd_unit *drhd) +{ + pci_sbdf_t sbdf; + unsigned int vtisochctrl; + + /* Only dedicated units are of interest. */ + if ( drhd->include_all || drhd->scope.devices_cnt != 1 ) + return true; + + /* Check for the specific device. */ + sbdf = PCI_SBDF2(drhd->segment, drhd->scope.devices[0]); + if ( pci_conf_read16(sbdf, PCI_VENDOR_ID) != PCI_VENDOR_ID_INTEL || + pci_conf_read16(sbdf, PCI_DEVICE_ID) != 0x3a3e ) + return true; + + /* Check for the corresponding System Management Registers device. */ + sbdf = PCI_SBDF(drhd->segment, 0, 0x14, 0); + if ( pci_conf_read16(sbdf, PCI_VENDOR_ID) != PCI_VENDOR_ID_INTEL || + pci_conf_read16(sbdf, PCI_DEVICE_ID) != 0x342e ) + return true; + + vtisochctrl = pci_conf_read32(sbdf, 0x188); + if ( vtisochctrl == 0xffffffff ) + { + printk(XENLOG_WARNING VTDPREFIX + " Cannot access VTISOCHCTRL at this time\n"); + return true; + } + + /* + * If Azalia DMA is routed to the non-isoch DMAR unit, that's fine in + * principle, but not consistent with the ACPI tables. + */ + if ( vtisochctrl & 1 ) + { + printk(XENLOG_WARNING VTDPREFIX + " Inconsistency between chipset registers and ACPI tables\n"); + return true; + } + + /* Drop all bits other than the number of TLB entries. */ + vtisochctrl &= 0x1c; + + /* If we have at least the recommended number of TLB entries, fine. */ + if ( vtisochctrl >= 16 ) + return true; + + /* Zero TLB entries? */ + if ( !vtisochctrl ) + return false; + + printk(XENLOG_WARNING VTDPREFIX + " Recommended TLB entries for ISOCH unit is 16; firmware set %u\n", + vtisochctrl); + + return true; +} + /* check for Sandybridge IGD device ID's */ static void __init snb_errata_init(void) { -- generated by git-patchbot for /home/xen/git/xen.git#staging
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |