From: Ian Campbell <ian.campbell@citrix.com>
To: xen-devel@lists.xen.org
Cc: Wei Wang <wei.wang2@amd.com>
Subject: [PATCH 4.0-testing 06/10] AMD IOMMU: Fix an interrupt remapping issue
Date: Mon, 11 Feb 2013 13:12:49 +0000 [thread overview]
Message-ID: <1360588373-779-6-git-send-email-ian.campbell@citrix.com> (raw)
In-Reply-To: <1360588355.20449.34.camel@zakaz.uk.xensource.com>
From: Wei Wang <wei.wang2@amd.com>
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>
xen-unstable changeset: 23200:995a0c01a076
xen-unstable date: Tue Apr 12 13:26:19 2011 +0100
---
xen/drivers/passthrough/amd/iommu_intr.c | 104 +++++++++++++++++------------
1 files changed, 61 insertions(+), 43 deletions(-)
diff --git a/xen/drivers/passthrough/amd/iommu_intr.c b/xen/drivers/passthrough/amd/iommu_intr.c
index 8c284d3..ceb6f47 100644
--- a/xen/drivers/passthrough/amd/iommu_intr.c
+++ b/xen/drivers/passthrough/amd/iommu_intr.c
@@ -116,8 +116,7 @@ void invalidate_interrupt_table(struct amd_iommu *iommu, u16 device_id)
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;
@@ -129,28 +128,26 @@ static void update_intremap_entry_from_ioapic(
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);
}
}
@@ -198,7 +195,8 @@ int __init amd_iommu_setup_ioapic_remapping(void)
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 )
@@ -216,16 +214,17 @@ int __init amd_iommu_setup_ioapic_remapping(void)
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)];
@@ -234,30 +233,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(
--
1.7.2.5
next prev parent reply other threads:[~2013-02-11 13:12 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-02-11 13:12 [PATCH 4.0-testing 00/10] XSA-{25, 27, 33, 36}: Backports for 4.0 (for Debian update) Ian Campbell
2013-02-11 13:12 ` [PATCH 4.0-testing 01/10] libxc: Do not use dom0 physmem as parameter to lzma decoder Ian Campbell
2013-02-11 13:12 ` [PATCH 4.0-testing 02/10] libxc: builder: limit maximum size of kernel/ramdisk Ian Campbell
2013-02-11 13:12 ` [PATCH 4.0-testing 03/10] hvm: Limit the size of large HVM op batches Ian Campbell
2013-02-11 13:12 ` [PATCH 4.0-testing 04/10] x86/mm: Fix loop increment in paging_log_dirty_range() Ian Campbell
2013-02-11 13:12 ` [PATCH 4.0-testing 05/10] VT-d: fix interrupt remapping source validation for devices behind legacy bridges Ian Campbell
2013-02-11 13:12 ` Ian Campbell [this message]
2013-02-11 13:12 ` [PATCH 4.0-testing 07/10] ACPI: acpi_table_parse() should return handler's error code Ian Campbell
2013-02-11 13:12 ` [PATCH 4.0-testing 08/10] AMD, IOMMU: Clean up old entries in remapping tables when creating new one Ian Campbell
2013-02-11 13:12 ` [PATCH 4.0-testing 09/10] AMD, IOMMU: Disable IOMMU if SATA Combined mode is on Ian Campbell
2013-02-11 13:12 ` [PATCH 4.0-testing 10/10] AMD, IOMMU: Make per-device interrupt remapping table default Ian Campbell
2013-02-12 9:44 ` [PATCH 4.0-testing 00/10] XSA-{25, 27, 33, 36}: Backports for 4.0 (for Debian update) Jan Beulich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1360588373-779-6-git-send-email-ian.campbell@citrix.com \
--to=ian.campbell@citrix.com \
--cc=wei.wang2@amd.com \
--cc=xen-devel@lists.xen.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).