[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] RE: [PATCH 2/2] VT-d: Tylersburg isoch DMAR unit with no TLB space
> From: Jan Beulich <jbeulich@xxxxxxxx> > Sent: Monday, October 11, 2021 4:50 PM > > 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> > --- > RFC: This requires MMCFG availability before Dom0 starts up, which is > not generally given. We may want/need to e.g. (ab)use the > .enable_device() hook to actually disable translation if MMCFG > accesses become available only in the course of Dom0 booting. make sense > RFC: While following Linux in this regard, I'm not convinced of issuing > the warning about the number of TLB entries when firmware set more > than 16 (I can observe 20 on the on matching system I have access > to.) me either. Since you already observed 20 on one system, changing the check to >=16 makes more sense. The rest looks good to me: Reviewed-by: Kevin Tian <kevin.tian@xxxxxxxxx> > > I assume an implication is that the device in this case then may not be > passed through to guests, but I don't see us enforcing the same anywhere > for graphics devices when "no-igfx" is in use. Yet here I would want to > follow whatever pre-existing model ... > > --- 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_d > 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); > --- a/xen/drivers/passthrough/vtd/iommu.c > +++ b/xen/drivers/passthrough/vtd/iommu.c > @@ -750,27 +750,43 @@ static void iommu_enable_translation(str > 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); > > --- a/xen/drivers/passthrough/vtd/quirks.c > +++ b/xen/drivers/passthrough/vtd/quirks.c > @@ -100,6 +100,69 @@ static void __init cantiga_b3_errata_ini > 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 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) > {
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |