11035112e8
51d277a3-x86-don-t-pass-negative-time-to-gtime_to_gtsc-try-2.patch 51d27807-iommu-amd-Fix-logic-for-clearing-the-IOMMU-interrupt-bits.patch 51d27841-iommu-amd-Workaround-for-erratum-787.patch 51daa074-Revert-hvmloader-always-include-HPET-table.patch - Dropped deprecated or unnecessary patches pvdrv-import-shared-info.patch minios-fixups.patch OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=258
286 lines
11 KiB
Diff
286 lines
11 KiB
Diff
# Commit 2823a0c7dfc979db316787e1dd42a8845e5825c0
|
|
# Date 2013-07-02 08:49:43 +0200
|
|
# Author Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
|
|
# Committer Jan Beulich <jbeulich@suse.com>
|
|
iommu/amd: Fix logic for clearing the IOMMU interrupt bits
|
|
|
|
The IOMMU interrupt bits in the IOMMU status registers are
|
|
"read-only, and write-1-to-clear (RW1C). Therefore, the existing
|
|
logic which reads the register, set the bit, and then writing back
|
|
the values could accidentally clear certain bits if it has been set.
|
|
|
|
The correct logic would just be writing only the value which only
|
|
set the interrupt bits, and leave the rest to zeros.
|
|
|
|
This patch also, clean up #define masks as Jan has suggested.
|
|
|
|
Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
|
|
|
|
With iommu_interrupt_handler() properly having got switched its readl()
|
|
from status to control register, the subsequent writel() needed to be
|
|
switched too (and the RW1C comment there was bogus).
|
|
|
|
Some of the cleanup went too far - undone.
|
|
|
|
Further, with iommu_interrupt_handler() now actually disabling the
|
|
interrupt sources, they also need to get re-enabled by the tasklet once
|
|
it finished processing the respective log. This also implies re-running
|
|
the tasklet so that log entries added between reading the log and re-
|
|
enabling the interrupt will get handled in a timely manner.
|
|
|
|
Finally, guest write emulation to the status register needs to be done
|
|
with the RW1C (and RO for all other bits) semantics in mind too.
|
|
|
|
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
|
Reviewed-by: Tim Deegan <tim@xen.org>
|
|
Acked-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
|
|
|
|
--- a/xen/drivers/passthrough/amd/iommu_cmd.c
|
|
+++ b/xen/drivers/passthrough/amd/iommu_cmd.c
|
|
@@ -75,11 +75,9 @@ static void flush_command_buffer(struct
|
|
u32 cmd[4], status;
|
|
int loop_count, comp_wait;
|
|
|
|
- /* clear 'ComWaitInt' in status register (WIC) */
|
|
- set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, 0,
|
|
- IOMMU_STATUS_COMP_WAIT_INT_MASK,
|
|
- IOMMU_STATUS_COMP_WAIT_INT_SHIFT, &status);
|
|
- writel(status, iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
|
|
+ /* RW1C 'ComWaitInt' in status register */
|
|
+ writel(IOMMU_STATUS_COMP_WAIT_INT_MASK,
|
|
+ iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
|
|
|
|
/* send an empty COMPLETION_WAIT command to flush command buffer */
|
|
cmd[3] = cmd[2] = 0;
|
|
@@ -103,9 +101,9 @@ static void flush_command_buffer(struct
|
|
|
|
if ( comp_wait )
|
|
{
|
|
- /* clear 'ComWaitInt' in status register (WIC) */
|
|
- status &= IOMMU_STATUS_COMP_WAIT_INT_MASK;
|
|
- writel(status, iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
|
|
+ /* RW1C 'ComWaitInt' in status register */
|
|
+ writel(IOMMU_STATUS_COMP_WAIT_INT_MASK,
|
|
+ iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
|
|
return;
|
|
}
|
|
AMD_IOMMU_DEBUG("Warning: ComWaitInt bit did not assert!\n");
|
|
--- a/xen/drivers/passthrough/amd/iommu_guest.c
|
|
+++ b/xen/drivers/passthrough/amd/iommu_guest.c
|
|
@@ -754,7 +754,14 @@ static void guest_iommu_mmio_write64(str
|
|
u64_to_reg(&iommu->ppr_log.reg_tail, val);
|
|
break;
|
|
case IOMMU_STATUS_MMIO_OFFSET:
|
|
- u64_to_reg(&iommu->reg_status, val);
|
|
+ val &= IOMMU_STATUS_EVENT_OVERFLOW_MASK |
|
|
+ IOMMU_STATUS_EVENT_LOG_INT_MASK |
|
|
+ IOMMU_STATUS_COMP_WAIT_INT_MASK |
|
|
+ IOMMU_STATUS_PPR_LOG_OVERFLOW_MASK |
|
|
+ IOMMU_STATUS_PPR_LOG_INT_MASK |
|
|
+ IOMMU_STATUS_GAPIC_LOG_OVERFLOW_MASK |
|
|
+ IOMMU_STATUS_GAPIC_LOG_INT_MASK;
|
|
+ u64_to_reg(&iommu->reg_status, reg_to_u64(iommu->reg_status) & ~val);
|
|
break;
|
|
|
|
default:
|
|
--- a/xen/drivers/passthrough/amd/iommu_init.c
|
|
+++ b/xen/drivers/passthrough/amd/iommu_init.c
|
|
@@ -344,13 +344,13 @@ static void set_iommu_ppr_log_control(st
|
|
writeq(0, iommu->mmio_base + IOMMU_PPR_LOG_TAIL_OFFSET);
|
|
|
|
iommu_set_bit(&entry, IOMMU_CONTROL_PPR_ENABLE_SHIFT);
|
|
- iommu_set_bit(&entry, IOMMU_CONTROL_PPR_INT_SHIFT);
|
|
+ iommu_set_bit(&entry, IOMMU_CONTROL_PPR_LOG_INT_SHIFT);
|
|
iommu_set_bit(&entry, IOMMU_CONTROL_PPR_LOG_ENABLE_SHIFT);
|
|
}
|
|
else
|
|
{
|
|
iommu_clear_bit(&entry, IOMMU_CONTROL_PPR_ENABLE_SHIFT);
|
|
- iommu_clear_bit(&entry, IOMMU_CONTROL_PPR_INT_SHIFT);
|
|
+ iommu_clear_bit(&entry, IOMMU_CONTROL_PPR_LOG_INT_SHIFT);
|
|
iommu_clear_bit(&entry, IOMMU_CONTROL_PPR_LOG_ENABLE_SHIFT);
|
|
}
|
|
|
|
@@ -410,7 +410,7 @@ static void iommu_reset_log(struct amd_i
|
|
void (*ctrl_func)(struct amd_iommu *iommu, int))
|
|
{
|
|
u32 entry;
|
|
- int log_run, run_bit, of_bit;
|
|
+ int log_run, run_bit;
|
|
int loop_count = 1000;
|
|
|
|
BUG_ON(!iommu || ((log != &iommu->event_log) && (log != &iommu->ppr_log)));
|
|
@@ -419,10 +419,6 @@ static void iommu_reset_log(struct amd_i
|
|
IOMMU_STATUS_EVENT_LOG_RUN_SHIFT :
|
|
IOMMU_STATUS_PPR_LOG_RUN_SHIFT;
|
|
|
|
- of_bit = ( log == &iommu->event_log ) ?
|
|
- IOMMU_STATUS_EVENT_OVERFLOW_SHIFT :
|
|
- IOMMU_STATUS_PPR_LOG_OVERFLOW_SHIFT;
|
|
-
|
|
/* wait until EventLogRun bit = 0 */
|
|
do {
|
|
entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
|
|
@@ -439,9 +435,10 @@ static void iommu_reset_log(struct amd_i
|
|
|
|
ctrl_func(iommu, IOMMU_CONTROL_DISABLED);
|
|
|
|
- /*clear overflow bit */
|
|
- iommu_clear_bit(&entry, of_bit);
|
|
- writel(entry, iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
|
|
+ /* RW1C overflow bit */
|
|
+ writel(log == &iommu->event_log ? IOMMU_STATUS_EVENT_OVERFLOW_MASK
|
|
+ : IOMMU_STATUS_PPR_LOG_OVERFLOW_MASK,
|
|
+ iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
|
|
|
|
/*reset event log base address */
|
|
log->head = 0;
|
|
@@ -611,22 +608,33 @@ static void iommu_check_event_log(struct
|
|
u32 entry;
|
|
unsigned long flags;
|
|
|
|
+ /* RW1C interrupt status bit */
|
|
+ writel(IOMMU_STATUS_EVENT_LOG_INT_MASK,
|
|
+ iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
|
|
+
|
|
iommu_read_log(iommu, &iommu->event_log,
|
|
sizeof(event_entry_t), parse_event_log_entry);
|
|
|
|
spin_lock_irqsave(&iommu->lock, flags);
|
|
|
|
- /*check event overflow */
|
|
+ /* Check event overflow. */
|
|
entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
|
|
-
|
|
if ( iommu_get_bit(entry, IOMMU_STATUS_EVENT_OVERFLOW_SHIFT) )
|
|
iommu_reset_log(iommu, &iommu->event_log, set_iommu_event_log_control);
|
|
-
|
|
- /* reset interrupt status bit */
|
|
- entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
|
|
- iommu_set_bit(&entry, IOMMU_STATUS_EVENT_LOG_INT_SHIFT);
|
|
-
|
|
- writel(entry, iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
|
|
+ else
|
|
+ {
|
|
+ entry = readl(iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
|
|
+ if ( !(entry & IOMMU_CONTROL_EVENT_LOG_INT_MASK) )
|
|
+ {
|
|
+ entry |= IOMMU_CONTROL_EVENT_LOG_INT_MASK;
|
|
+ writel(entry, iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
|
|
+ /*
|
|
+ * Re-schedule the tasklet to handle eventual log entries added
|
|
+ * between reading the log above and re-enabling the interrupt.
|
|
+ */
|
|
+ tasklet_schedule(&amd_iommu_irq_tasklet);
|
|
+ }
|
|
+ }
|
|
|
|
spin_unlock_irqrestore(&iommu->lock, flags);
|
|
}
|
|
@@ -681,22 +689,33 @@ static void iommu_check_ppr_log(struct a
|
|
u32 entry;
|
|
unsigned long flags;
|
|
|
|
+ /* RW1C interrupt status bit */
|
|
+ writel(IOMMU_STATUS_PPR_LOG_INT_MASK,
|
|
+ iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
|
|
+
|
|
iommu_read_log(iommu, &iommu->ppr_log,
|
|
sizeof(ppr_entry_t), parse_ppr_log_entry);
|
|
|
|
spin_lock_irqsave(&iommu->lock, flags);
|
|
|
|
- /*check event overflow */
|
|
+ /* Check event overflow. */
|
|
entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
|
|
-
|
|
if ( iommu_get_bit(entry, IOMMU_STATUS_PPR_LOG_OVERFLOW_SHIFT) )
|
|
iommu_reset_log(iommu, &iommu->ppr_log, set_iommu_ppr_log_control);
|
|
-
|
|
- /* reset interrupt status bit */
|
|
- entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
|
|
- iommu_set_bit(&entry, IOMMU_STATUS_PPR_LOG_INT_SHIFT);
|
|
-
|
|
- writel(entry, iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
|
|
+ else
|
|
+ {
|
|
+ entry = readl(iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
|
|
+ if ( !(entry & IOMMU_CONTROL_PPR_LOG_INT_MASK) )
|
|
+ {
|
|
+ entry |= IOMMU_CONTROL_PPR_LOG_INT_MASK;
|
|
+ writel(entry, iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
|
|
+ /*
|
|
+ * Re-schedule the tasklet to handle eventual log entries added
|
|
+ * between reading the log above and re-enabling the interrupt.
|
|
+ */
|
|
+ tasklet_schedule(&amd_iommu_irq_tasklet);
|
|
+ }
|
|
+ }
|
|
|
|
spin_unlock_irqrestore(&iommu->lock, flags);
|
|
}
|
|
@@ -733,11 +752,14 @@ static void iommu_interrupt_handler(int
|
|
|
|
spin_lock_irqsave(&iommu->lock, flags);
|
|
|
|
- /* Silence interrupts from both event and PPR logging */
|
|
- entry = readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
|
|
- iommu_clear_bit(&entry, IOMMU_STATUS_EVENT_LOG_INT_SHIFT);
|
|
- iommu_clear_bit(&entry, IOMMU_STATUS_PPR_LOG_INT_SHIFT);
|
|
- writel(entry, iommu->mmio_base+IOMMU_STATUS_MMIO_OFFSET);
|
|
+ /*
|
|
+ * Silence interrupts from both event and PPR by clearing the
|
|
+ * enable logging bits in the control register
|
|
+ */
|
|
+ entry = readl(iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
|
|
+ iommu_clear_bit(&entry, IOMMU_CONTROL_EVENT_LOG_INT_SHIFT);
|
|
+ iommu_clear_bit(&entry, IOMMU_CONTROL_PPR_LOG_INT_SHIFT);
|
|
+ writel(entry, iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET);
|
|
|
|
spin_unlock_irqrestore(&iommu->lock, flags);
|
|
|
|
--- a/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
|
|
+++ b/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h
|
|
@@ -336,14 +336,17 @@
|
|
#define IOMMU_CONTROL_ISOCHRONOUS_SHIFT 11
|
|
#define IOMMU_CONTROL_COMMAND_BUFFER_ENABLE_MASK 0x00001000
|
|
#define IOMMU_CONTROL_COMMAND_BUFFER_ENABLE_SHIFT 12
|
|
+#define IOMMU_CONTROL_PPR_LOG_ENABLE_MASK 0x00002000
|
|
+#define IOMMU_CONTROL_PPR_LOG_ENABLE_SHIFT 13
|
|
+#define IOMMU_CONTROL_PPR_LOG_INT_MASK 0x00004000
|
|
+#define IOMMU_CONTROL_PPR_LOG_INT_SHIFT 14
|
|
+#define IOMMU_CONTROL_PPR_ENABLE_MASK 0x00008000
|
|
+#define IOMMU_CONTROL_PPR_ENABLE_SHIFT 15
|
|
+#define IOMMU_CONTROL_GT_ENABLE_MASK 0x00010000
|
|
+#define IOMMU_CONTROL_GT_ENABLE_SHIFT 16
|
|
#define IOMMU_CONTROL_RESTART_MASK 0x80000000
|
|
#define IOMMU_CONTROL_RESTART_SHIFT 31
|
|
|
|
-#define IOMMU_CONTROL_PPR_LOG_ENABLE_SHIFT 13
|
|
-#define IOMMU_CONTROL_PPR_INT_SHIFT 14
|
|
-#define IOMMU_CONTROL_PPR_ENABLE_SHIFT 15
|
|
-#define IOMMU_CONTROL_GT_ENABLE_SHIFT 16
|
|
-
|
|
/* Exclusion Register */
|
|
#define IOMMU_EXCLUSION_BASE_LOW_OFFSET 0x20
|
|
#define IOMMU_EXCLUSION_BASE_HIGH_OFFSET 0x24
|
|
@@ -395,9 +398,18 @@
|
|
#define IOMMU_STATUS_EVENT_LOG_RUN_SHIFT 3
|
|
#define IOMMU_STATUS_CMD_BUFFER_RUN_MASK 0x00000010
|
|
#define IOMMU_STATUS_CMD_BUFFER_RUN_SHIFT 4
|
|
+#define IOMMU_STATUS_PPR_LOG_OVERFLOW_MASK 0x00000020
|
|
#define IOMMU_STATUS_PPR_LOG_OVERFLOW_SHIFT 5
|
|
+#define IOMMU_STATUS_PPR_LOG_INT_MASK 0x00000040
|
|
#define IOMMU_STATUS_PPR_LOG_INT_SHIFT 6
|
|
+#define IOMMU_STATUS_PPR_LOG_RUN_MASK 0x00000080
|
|
#define IOMMU_STATUS_PPR_LOG_RUN_SHIFT 7
|
|
+#define IOMMU_STATUS_GAPIC_LOG_OVERFLOW_MASK 0x00000100
|
|
+#define IOMMU_STATUS_GAPIC_LOG_OVERFLOW_SHIFT 8
|
|
+#define IOMMU_STATUS_GAPIC_LOG_INT_MASK 0x00000200
|
|
+#define IOMMU_STATUS_GAPIC_LOG_INT_SHIFT 9
|
|
+#define IOMMU_STATUS_GAPIC_LOG_RUN_MASK 0x00000400
|
|
+#define IOMMU_STATUS_GAPIC_LOG_RUN_SHIFT 10
|
|
|
|
/* I/O Page Table */
|
|
#define IOMMU_PAGE_TABLE_ENTRY_SIZE 8
|