diff options
-rw-r--r-- | xen/drivers/passthrough/amd/iommu_init.c | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/xen/drivers/passthrough/amd/iommu_init.c b/xen/drivers/passthrough/amd/iommu_init.c index 282c04c0b2..31acec9310 100644 --- a/xen/drivers/passthrough/amd/iommu_init.c +++ b/xen/drivers/passthrough/amd/iommu_init.c @@ -636,6 +636,42 @@ static int set_iommu_interrupt_handler(struct amd_iommu *iommu) return irq; } +/* + * Family15h Model 10h-1fh erratum 746 (IOMMU Logging May Stall Translations) + * Workaround: + * BIOS should disable L2B micellaneous clock gating by setting + * L2_L2B_CK_GATE_CONTROL[CKGateL2BMiscDisable](D0F2xF4_x90[2]) = 1b + */ +static void amd_iommu_erratum_746_workaround(struct amd_iommu *iommu) +{ + u32 value; + u8 bus = PCI_BUS(iommu->bdf); + u8 dev = PCI_SLOT(iommu->bdf); + u8 func = PCI_FUNC(iommu->bdf); + + if ( (boot_cpu_data.x86 != 0x15) || + (boot_cpu_data.x86_model < 0x10) || + (boot_cpu_data.x86_model > 0x1f) ) + return; + + pci_conf_write32(bus, dev, func, 0xf0, 0x90); + value = pci_conf_read32(bus, dev, func, 0xf4); + + if ( value & (1 << 2) ) + return; + + /* Select NB indirect register 0x90 and enable writing */ + pci_conf_write32(bus, dev, func, 0xf0, 0x90 | (1 << 8)); + + pci_conf_write32(bus, dev, func, 0xf4, value | (1 << 2)); + printk(XENLOG_INFO + "AMD-Vi: Applying erratum 746 workaround for IOMMU at %02x:%02x.%u\n", + bus, dev, func); + + /* Clear the enable writing bit */ + pci_conf_write32(bus, dev, func, 0xf0, 0x90); +} + static void enable_iommu(struct amd_iommu *iommu) { unsigned long flags; @@ -648,6 +684,8 @@ static void enable_iommu(struct amd_iommu *iommu) return; } + amd_iommu_erratum_746_workaround(iommu); + register_iommu_dev_table_in_mmio_space(iommu); register_iommu_cmd_buffer_in_mmio_space(iommu); register_iommu_event_log_in_mmio_space(iommu); |