4c73609012
22998-x86-get_page_from_l1e-retcode.patch 22999-x86-mod_l1_entry-retcode.patch 23000-x86-mod_l2_entry-retcode.patch 23096-x86-hpet-no-cpumask_lock.patch 23099-x86-rwlock-scalability.patch 23103-x86-pirq-guest-eoi-check.patch 23127-vtd-bios-settings.patch 23153-x86-amd-clear-DramModEn.patch 23154-x86-amd-iorr-no-rdwr.patch 23199-amd-iommu-unmapped-intr-fault.patch 23200-amd-iommu-intremap-sync.patch 23228-x86-conditional-write_tsc.patch - update xenalyze to revision 98 * Unify setting of vcpu data type * Unify record size checks * Fix cr3_switch not to access hvm struct before it's initialized - add xenalyze.gcc46.patch to fix unused-but-set-variable errors - bnc#688473 - VUL-0: potential buffer overflow in tools cve-2011-1583-4.0.patch - hotplug.losetup.patch correct dev:inode detection and use variable expansion OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=115
180 lines
6.2 KiB
Diff
180 lines
6.2 KiB
Diff
References: bnc#680824
|
|
|
|
# HG changeset patch
|
|
# User Wei Wang <wei.wang2@amd.com>
|
|
# Date 1302611179 -3600
|
|
# Node ID 995a0c01a076e9c4fb124c090bc146a10d76bc7b
|
|
# Parent dbd98ab2f87facba8117bb881fa2ea5dfdb92960
|
|
AMD IOMMU: Fix an interrupt remapping issue
|
|
|
|
Some device could generate bogus interrupts if an IO-APIC RTE and an
|
|
iommu interrupt remapping entry are not consistent during 2 adjacent
|
|
64bits IO-APIC RTE updates. For example, if the 2nd operation updates
|
|
destination bits in RTE for SATA device and unmask it, in some case,
|
|
SATA device will assert ioapic pin to generate interrupt immediately
|
|
using new destination but iommu could still translate it into the old
|
|
destination, then dom0 would be confused. To fix that, we sync up
|
|
interrupt remapping entry with IO-APIC IRE on every 32 bits operation
|
|
and forward IOAPIC RTE updates after interrupt.
|
|
|
|
Signed-off-by: Wei Wang <wei.wang2@amd.com>
|
|
Acked-by: Jan Beulich <jbeulich@novell.com>
|
|
|
|
--- a/xen/drivers/passthrough/amd/iommu_intr.c
|
|
+++ b/xen/drivers/passthrough/amd/iommu_intr.c
|
|
@@ -117,8 +117,7 @@ void invalidate_interrupt_table(struct a
|
|
static void update_intremap_entry_from_ioapic(
|
|
int bdf,
|
|
struct amd_iommu *iommu,
|
|
- struct IO_APIC_route_entry *ioapic_rte,
|
|
- unsigned int rte_upper, unsigned int value)
|
|
+ struct IO_APIC_route_entry *ioapic_rte)
|
|
{
|
|
unsigned long flags;
|
|
u32* entry;
|
|
@@ -130,28 +129,26 @@ static void update_intremap_entry_from_i
|
|
|
|
req_id = get_intremap_requestor_id(bdf);
|
|
lock = get_intremap_lock(req_id);
|
|
- /* only remap interrupt vector when lower 32 bits in ioapic ire changed */
|
|
- if ( likely(!rte_upper) )
|
|
- {
|
|
- delivery_mode = rte->delivery_mode;
|
|
- vector = rte->vector;
|
|
- dest_mode = rte->dest_mode;
|
|
- dest = rte->dest.logical.logical_dest;
|
|
|
|
- spin_lock_irqsave(lock, flags);
|
|
- offset = get_intremap_offset(vector, delivery_mode);
|
|
- entry = (u32*)get_intremap_entry(req_id, offset);
|
|
+ delivery_mode = rte->delivery_mode;
|
|
+ vector = rte->vector;
|
|
+ dest_mode = rte->dest_mode;
|
|
+ dest = rte->dest.logical.logical_dest;
|
|
|
|
- update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest);
|
|
- spin_unlock_irqrestore(lock, flags);
|
|
+ spin_lock_irqsave(lock, flags);
|
|
|
|
- if ( iommu->enabled )
|
|
- {
|
|
- spin_lock_irqsave(&iommu->lock, flags);
|
|
- invalidate_interrupt_table(iommu, req_id);
|
|
- flush_command_buffer(iommu);
|
|
- spin_unlock_irqrestore(&iommu->lock, flags);
|
|
- }
|
|
+ offset = get_intremap_offset(vector, delivery_mode);
|
|
+ entry = (u32*)get_intremap_entry(req_id, offset);
|
|
+ update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest);
|
|
+
|
|
+ spin_unlock_irqrestore(lock, flags);
|
|
+
|
|
+ if ( iommu->enabled )
|
|
+ {
|
|
+ spin_lock_irqsave(&iommu->lock, flags);
|
|
+ invalidate_interrupt_table(iommu, req_id);
|
|
+ flush_command_buffer(iommu);
|
|
+ spin_unlock_irqrestore(&iommu->lock, flags);
|
|
}
|
|
}
|
|
|
|
@@ -199,7 +196,8 @@ int __init amd_iommu_setup_ioapic_remapp
|
|
spin_lock_irqsave(lock, flags);
|
|
offset = get_intremap_offset(vector, delivery_mode);
|
|
entry = (u32*)get_intremap_entry(req_id, offset);
|
|
- update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest);
|
|
+ update_intremap_entry(entry, vector,
|
|
+ delivery_mode, dest_mode, dest);
|
|
spin_unlock_irqrestore(lock, flags);
|
|
|
|
if ( iommu->enabled )
|
|
@@ -217,16 +215,17 @@ int __init amd_iommu_setup_ioapic_remapp
|
|
void amd_iommu_ioapic_update_ire(
|
|
unsigned int apic, unsigned int reg, unsigned int value)
|
|
{
|
|
- struct IO_APIC_route_entry ioapic_rte = { 0 };
|
|
- unsigned int rte_upper = (reg & 1) ? 1 : 0;
|
|
+ struct IO_APIC_route_entry old_rte = { 0 };
|
|
+ struct IO_APIC_route_entry new_rte = { 0 };
|
|
+ unsigned int rte_lo = (reg & 1) ? reg - 1 : reg;
|
|
int saved_mask, bdf;
|
|
struct amd_iommu *iommu;
|
|
|
|
- *IO_APIC_BASE(apic) = reg;
|
|
- *(IO_APIC_BASE(apic)+4) = value;
|
|
-
|
|
if ( !iommu_intremap )
|
|
+ {
|
|
+ __io_apic_write(apic, reg, value);
|
|
return;
|
|
+ }
|
|
|
|
/* get device id of ioapic devices */
|
|
bdf = ioapic_bdf[IO_APIC_ID(apic)];
|
|
@@ -235,30 +234,49 @@ void amd_iommu_ioapic_update_ire(
|
|
{
|
|
AMD_IOMMU_DEBUG("Fail to find iommu for ioapic device id = 0x%x\n",
|
|
bdf);
|
|
+ __io_apic_write(apic, reg, value);
|
|
return;
|
|
}
|
|
- if ( rte_upper )
|
|
- return;
|
|
|
|
- /* read both lower and upper 32-bits of rte entry */
|
|
- *IO_APIC_BASE(apic) = reg;
|
|
- *(((u32 *)&ioapic_rte) + 0) = *(IO_APIC_BASE(apic)+4);
|
|
- *IO_APIC_BASE(apic) = reg + 1;
|
|
- *(((u32 *)&ioapic_rte) + 1) = *(IO_APIC_BASE(apic)+4);
|
|
+ /* save io-apic rte lower 32 bits */
|
|
+ *((u32 *)&old_rte) = __io_apic_read(apic, rte_lo);
|
|
+ saved_mask = old_rte.mask;
|
|
+
|
|
+ if ( reg == rte_lo )
|
|
+ {
|
|
+ *((u32 *)&new_rte) = value;
|
|
+ /* read upper 32 bits from io-apic rte */
|
|
+ *(((u32 *)&new_rte) + 1) = __io_apic_read(apic, reg + 1);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ *((u32 *)&new_rte) = *((u32 *)&old_rte);
|
|
+ *(((u32 *)&new_rte) + 1) = value;
|
|
+ }
|
|
|
|
/* mask the interrupt while we change the intremap table */
|
|
- saved_mask = ioapic_rte.mask;
|
|
- ioapic_rte.mask = 1;
|
|
- *IO_APIC_BASE(apic) = reg;
|
|
- *(IO_APIC_BASE(apic)+4) = *(((int *)&ioapic_rte)+0);
|
|
- ioapic_rte.mask = saved_mask;
|
|
+ if ( !saved_mask )
|
|
+ {
|
|
+ old_rte.mask = 1;
|
|
+ __io_apic_write(apic, rte_lo, *((u32 *)&old_rte));
|
|
+ }
|
|
|
|
- update_intremap_entry_from_ioapic(
|
|
- bdf, iommu, &ioapic_rte, rte_upper, value);
|
|
+ /* Update interrupt remapping entry */
|
|
+ update_intremap_entry_from_ioapic(bdf, iommu, &new_rte);
|
|
+
|
|
+ /* Forward write access to IO-APIC RTE */
|
|
+ __io_apic_write(apic, reg, value);
|
|
+
|
|
+ /* For lower bits access, return directly to avoid double writes */
|
|
+ if ( reg == rte_lo )
|
|
+ return;
|
|
|
|
/* unmask the interrupt after we have updated the intremap table */
|
|
- *IO_APIC_BASE(apic) = reg;
|
|
- *(IO_APIC_BASE(apic)+4) = *(((u32 *)&ioapic_rte)+0);
|
|
+ if ( !saved_mask )
|
|
+ {
|
|
+ old_rte.mask = saved_mask;
|
|
+ __io_apic_write(apic, rte_lo, *((u32 *)&old_rte));
|
|
+ }
|
|
}
|
|
|
|
static void update_intremap_entry_from_msi_msg(
|