summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJoerg Roedel <joerg.roedel@amd.com>2012-04-12 14:12:00 +0200
committerJoerg Roedel <joerg.roedel@amd.com>2012-04-12 14:16:14 +0200
commit3d06fca8d2aa3543030e40b95f1d62f9f5a03540 (patch)
treefcef864e872b18c00991cc1805c279f977e61fca /drivers
parenta3b93121430c7b46c2895a7744261be107ccdf7f (diff)
downloadlinux-3d06fca8d2aa3543030e40b95f1d62f9f5a03540.tar.gz
linux-3d06fca8d2aa3543030e40b95f1d62f9f5a03540.tar.bz2
linux-3d06fca8d2aa3543030e40b95f1d62f9f5a03540.zip
iommu/amd: Add workaround for event log erratum
Due to a recent erratum it can happen that the head pointer of the event-log is updated before the actual event-log entry is written. This patch implements the recommended workaround. Cc: stable@vger.kernel.org # all stable kernels Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/iommu/amd_iommu.c29
1 files changed, 23 insertions, 6 deletions
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 08f3eecb87a2..d90a421e9cac 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -450,12 +450,27 @@ static void dump_command(unsigned long phys_addr)
static void iommu_print_event(struct amd_iommu *iommu, void *__evt)
{
- u32 *event = __evt;
- int type = (event[1] >> EVENT_TYPE_SHIFT) & EVENT_TYPE_MASK;
- int devid = (event[0] >> EVENT_DEVID_SHIFT) & EVENT_DEVID_MASK;
- int domid = (event[1] >> EVENT_DOMID_SHIFT) & EVENT_DOMID_MASK;
- int flags = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK;
- u64 address = (u64)(((u64)event[3]) << 32) | event[2];
+ int type, devid, domid, flags;
+ volatile u32 *event = __evt;
+ int count = 0;
+ u64 address;
+
+retry:
+ type = (event[1] >> EVENT_TYPE_SHIFT) & EVENT_TYPE_MASK;
+ devid = (event[0] >> EVENT_DEVID_SHIFT) & EVENT_DEVID_MASK;
+ domid = (event[1] >> EVENT_DOMID_SHIFT) & EVENT_DOMID_MASK;
+ flags = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK;
+ address = (u64)(((u64)event[3]) << 32) | event[2];
+
+ if (type == 0) {
+ /* Did we hit the erratum? */
+ if (++count == LOOP_TIMEOUT) {
+ pr_err("AMD-Vi: No event written to event log\n");
+ return;
+ }
+ udelay(1);
+ goto retry;
+ }
printk(KERN_ERR "AMD-Vi: Event logged [");
@@ -508,6 +523,8 @@ static void iommu_print_event(struct amd_iommu *iommu, void *__evt)
default:
printk(KERN_ERR "UNKNOWN type=0x%02x]\n", type);
}
+
+ memset(__evt, 0, 4 * sizeof(u32));
}
static void iommu_poll_events(struct amd_iommu *iommu)