IOMMU, AMD Family15h Model10-1Fh erratum 746 Workaround
authorSuravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Tue, 26 Feb 2013 09:14:53 +0000 (10:14 +0100)
committerJan Beulich <jbeulich@suse.com>
Tue, 26 Feb 2013 09:14:53 +0000 (10:14 +0100)
The IOMMU may stop processing page translations due to a perceived lack
of credits for writing upstream peripheral page service request (PPR)
or event logs. If the L2B miscellaneous clock gating feature is enabled
the IOMMU does not properly register credits after the log request has
completed, leading to a potential system hang.

BIOSes are supposed to disable L2B micellaneous clock gating by setting
L2_L2B_CK_GATE_CONTROL[CKGateL2BMiscDisable](D0F2xF4_x90[2]) = 1b. This
patch corrects that for those which do not enable this workaround.

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
xen/drivers/passthrough/amd/iommu_init.c

index 137531a42f994045959a03d1abeecf3116879852..e0986d85d1c601b7c57dd60dcf89321d51f6fe5d 100644 (file)
@@ -792,6 +792,42 @@ static bool_t __init set_iommu_interrupt_handler(struct amd_iommu *iommu)
     return 1;
 }
 
+/*
+ * 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(iommu->seg, bus, dev, func, 0xf0, 0x90);
+    value = pci_conf_read32(iommu->seg, bus, dev, func, 0xf4);
+
+    if ( value & (1 << 2) )
+        return;
+
+    /* Select NB indirect register 0x90 and enable writing */
+    pci_conf_write32(iommu->seg, bus, dev, func, 0xf0, 0x90 | (1 << 8));
+
+    pci_conf_write32(iommu->seg, bus, dev, func, 0xf4, value | (1 << 2));
+    printk(XENLOG_INFO
+           "AMD-Vi: Applying erratum 746 workaround for IOMMU at %04x:%02x:%02x.%u\n",
+           iommu->seg, bus, dev, func);
+
+    /* Clear the enable writing bit */
+    pci_conf_write32(iommu->seg, bus, dev, func, 0xf0, 0x90);
+}
+
 static void enable_iommu(struct amd_iommu *iommu)
 {
     unsigned long flags;
@@ -805,6 +841,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);