aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--xen/drivers/passthrough/amd/iommu_init.c38
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);