[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-3.4-testing] AMD IOMMU: Reset event logging when event overflows



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1262596167 0
# Node ID a7b2d4e03a1f4d0b4796378aa1cfc8e2908d4624
# Parent  a5b0c000a9d90d949fc4f47d4ba3424ee1258dea
AMD IOMMU: Reset event logging when event overflows

Restart iommu event logging if EventOverFlow bit is set to prevent
event logging from being disabled after event overflows.

Signed-off-by: Wei Wang <wei.wang2@xxxxxxx>
xen-unstable changeset:   20653:84de9733e3ee
xen-unstable date:        Wed Dec 16 16:47:31 2009 +0000
---
 xen/drivers/passthrough/amd/iommu_init.c |   92 ++++++++++++++++++++++---------
 1 files changed, 68 insertions(+), 24 deletions(-)

diff -r a5b0c000a9d9 -r a7b2d4e03a1f xen/drivers/passthrough/amd/iommu_init.c
--- a/xen/drivers/passthrough/amd/iommu_init.c  Wed Dec 30 13:21:41 2009 +0000
+++ b/xen/drivers/passthrough/amd/iommu_init.c  Mon Jan 04 09:09:27 2010 +0000
@@ -270,26 +270,65 @@ static void set_iommu_event_log_control(
     writel(entry, iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
 }
 
-static int amd_iommu_read_event_log(struct amd_iommu *iommu, u32 event[])
+static void amd_iommu_reset_event_log(struct amd_iommu *iommu)
+{
+    u32 entry;
+    int log_run;
+    int loop_count = 1000;
+
+    /* wait until EventLogRun bit = 0 */
+    do {
+        entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
+        log_run = get_field_from_reg_u32(entry,
+                                        IOMMU_STATUS_EVENT_LOG_RUN_MASK,
+                                        IOMMU_STATUS_EVENT_LOG_RUN_SHIFT);
+        loop_count--;
+    } while ( log_run && loop_count );
+
+    if ( log_run )
+    {
+        AMD_IOMMU_DEBUG("Warning: EventLogRun bit is not cleared"
+                       "before reset!\n");
+        return;
+    }
+
+    set_iommu_event_log_control(iommu, IOMMU_CONTROL_DISABLED);
+
+    /*clear overflow bit */
+    set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, entry,
+                         IOMMU_STATUS_EVENT_OVERFLOW_MASK,
+                         IOMMU_STATUS_EVENT_OVERFLOW_SHIFT, &entry);
+    writel(entry, iommu->mmio_base+IOMMU_STATUS_MMIO_OFFSET);
+
+    /*reset event log base address */
+    iommu->event_log_head = 0;
+
+    set_iommu_event_log_control(iommu, IOMMU_CONTROL_ENABLED);
+}
+
+static void parse_event_log_entry(u32 entry[]);
+
+static int amd_iommu_read_event_log(struct amd_iommu *iommu)
 {
     u32 tail, head, *event_log;
-    int i;
-
-     BUG_ON( !iommu || !event );
+
+    BUG_ON( !iommu );
 
     /* make sure there's an entry in the log */
-    tail = get_field_from_reg_u32(
-                readl(iommu->mmio_base + IOMMU_EVENT_LOG_TAIL_OFFSET),
-                IOMMU_EVENT_LOG_TAIL_MASK,
-                IOMMU_EVENT_LOG_TAIL_SHIFT);
-    if ( tail != iommu->event_log_head )
+    tail = readl(iommu->mmio_base + IOMMU_EVENT_LOG_TAIL_OFFSET);
+    tail = get_field_from_reg_u32(tail,
+                                  IOMMU_EVENT_LOG_TAIL_MASK,
+                                  IOMMU_EVENT_LOG_TAIL_SHIFT);
+
+    while ( tail != iommu->event_log_head )
     {
         /* read event log entry */
         event_log = (u32 *)(iommu->event_log.buffer +
-                                        (iommu->event_log_head *
-                                        IOMMU_EVENT_LOG_ENTRY_SIZE));
-        for ( i = 0; i < IOMMU_EVENT_LOG_U32_PER_ENTRY; i++ )
-            event[i] = event_log[i];
+                           (iommu->event_log_head *
+                           IOMMU_EVENT_LOG_ENTRY_SIZE));
+
+        parse_event_log_entry(event_log);
+
         if ( ++iommu->event_log_head == iommu->event_log.entries )
             iommu->event_log_head = 0;
 
@@ -298,10 +337,9 @@ static int amd_iommu_read_event_log(stru
                              IOMMU_EVENT_LOG_HEAD_MASK,
                              IOMMU_EVENT_LOG_HEAD_SHIFT, &head);
         writel(head, iommu->mmio_base + IOMMU_EVENT_LOG_HEAD_OFFSET);
-        return 0;
-    }
-
-    return -EFAULT;
+    }
+
+    return 0;
 }
 
 static void amd_iommu_msi_data_init(struct amd_iommu *iommu)
@@ -455,14 +493,24 @@ static void amd_iommu_page_fault(int vec
 static void amd_iommu_page_fault(int vector, void *dev_id,
                              struct cpu_user_regs *regs)
 {
-    u32 event[4];
     u32 entry;
     unsigned long flags;
-    int ret = 0;
+    int of;
     struct amd_iommu *iommu = dev_id;
 
     spin_lock_irqsave(&iommu->lock, flags);
-    ret = amd_iommu_read_event_log(iommu, event);
+    amd_iommu_read_event_log(iommu);
+
+    /*check event overflow */
+    entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
+    of = get_field_from_reg_u32(entry,
+                               IOMMU_STATUS_EVENT_OVERFLOW_MASK,
+                               IOMMU_STATUS_EVENT_OVERFLOW_SHIFT);
+
+    /* reset event log if event overflow */
+    if ( of )
+        amd_iommu_reset_event_log(iommu);
+
     /* reset interrupt status bit */
     entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
     set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
@@ -470,10 +518,6 @@ static void amd_iommu_page_fault(int vec
                          IOMMU_STATUS_EVENT_LOG_INT_SHIFT, &entry);
     writel(entry, iommu->mmio_base+IOMMU_STATUS_MMIO_OFFSET);
     spin_unlock_irqrestore(&iommu->lock, flags);
-
-    if ( ret != 0 )
-        return;
-    parse_event_log_entry(event);
 }
 
 static int set_iommu_interrupt_handler(struct amd_iommu *iommu)

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.