AMD IOMMU: Fix event log interrupt handling
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 3 Dec 2008 15:55:32 +0000 (15:55 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 3 Dec 2008 15:55:32 +0000 (15:55 +0000)
Reset EventLogInt bit in iommu status register(MMIO offset 2020h) in
event log interrupt handler, to show software has handled the
interrupt. Completion wait interrupt is disabled.

Signed-off-by: Wei Wang <wei.wang2@amd.com>
xen/drivers/passthrough/amd/iommu_init.c

index 0a2081fe39446b0c086514054f70df1548d91362..3b6349801bdf42175872083e811f5aa215135faa 100644 (file)
@@ -235,8 +235,7 @@ static void __init set_iommu_event_log_control(struct amd_iommu *iommu,
                          IOMMU_CONTROL_EVENT_LOG_INT_SHIFT, &entry);
     writel(entry, iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET);
 
-    set_field_in_reg_u32(enable ? IOMMU_CONTROL_ENABLED :
-                         IOMMU_CONTROL_DISABLED, entry,
+    set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, entry,
                          IOMMU_CONTROL_COMP_WAIT_INT_MASK,
                          IOMMU_CONTROL_COMP_WAIT_INT_SHIFT, &entry);
     writel(entry, iommu->mmio_base+IOMMU_CONTROL_MMIO_OFFSET);
@@ -391,20 +390,19 @@ static void parse_event_log_entry(u32 entry[])
     u32 code;
     u64 *addr;
     char * event_str[] = {"ILLEGAL_DEV_TABLE_ENTRY",
-                                         "IO_PAGE_FALT",
-                                         "DEV_TABLE_HW_ERROR",
-                                         "PAGE_TABLE_HW_ERROR",
-                                         "ILLEGAL_COMMAND_ERROR",
-                                         "COMMAND_HW_ERROR",
-                                         "IOTLB_INV_TIMEOUT",
-                                         "INVALID_DEV_REQUEST"};
-
-    code = get_field_from_reg_u32(entry[1],
-                                           IOMMU_EVENT_CODE_MASK,
-                                           IOMMU_EVENT_CODE_SHIFT);
-
-    if ( (code > IOMMU_EVENT_INVALID_DEV_REQUEST)
-        || (code < IOMMU_EVENT_ILLEGAL_DEV_TABLE_ENTRY) )
+                          "IO_PAGE_FALT",
+                          "DEV_TABLE_HW_ERROR",
+                          "PAGE_TABLE_HW_ERROR",
+                          "ILLEGAL_COMMAND_ERROR",
+                          "COMMAND_HW_ERROR",
+                          "IOTLB_INV_TIMEOUT",
+                          "INVALID_DEV_REQUEST"};
+
+    code = get_field_from_reg_u32(entry[1], IOMMU_EVENT_CODE_MASK,
+                                            IOMMU_EVENT_CODE_SHIFT);
+
+    if ( (code > IOMMU_EVENT_INVALID_DEV_REQUEST) ||
+        (code < IOMMU_EVENT_ILLEGAL_DEV_TABLE_ENTRY) )
     {
         amd_iov_error("Invalid event log entry!\n");
         return;
@@ -428,13 +426,20 @@ static void parse_event_log_entry(u32 entry[])
 static void amd_iommu_page_fault(int vector, void *dev_id,
                              struct cpu_user_regs *regs)
 {
-    u32  event[4];
+    u32 event[4];
+    u32 entry;
     unsigned long flags;
     int ret = 0;
     struct amd_iommu *iommu = dev_id;
 
     spin_lock_irqsave(&iommu->lock, flags);
     ret = amd_iommu_read_event_log(iommu, event);
+    /* reset interrupt status bit */
+    entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
+    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
+                         IOMMU_STATUS_EVENT_LOG_INT_MASK,
+                         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 )
@@ -466,7 +471,7 @@ static int set_iommu_interrupt_handler(struct amd_iommu *iommu)
         amd_iov_error("can't request irq\n");
         return 0;
     }
-
+    iommu->vector = vector;
     return vector;
 }