# 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
|