# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1238496852 -3600
# Node ID 57b733f66531ca437bcd9015b728bf6a62e4d37f
# Parent f6a2bf60d49cfd05bb36ecafb3598139ca142804
vtd: fix multiple Dom0 S3 on hosts that support Queued Invalidation.
On such hosts we can't do multiple Dom0 S3 when VT-d is enabled.
The cause is: during the first S3 resume, init_vtd_hw() initializes
the invalidation function pointers to the register-based ones and later
enable_qinval() forgets to overwrite the flush function pointers to
queued-based ones, so actually Queued Invalidaton is enabled, but we
actually use the register-based invalidation function! Later during
the second Dom0 S3, in iommu_suspend() -> iommu_flush_all(), we try to
use the register-based invalidation functions to perform global flush
while Queued Invalidation is enabled, and this can cause a host reset
because VT-d spec says: when the queued invalidation is enabled,
software must submit invalidation commands only through the IQ (and
not through any invalidation command registers).
The attached patch fixes the buggy enable_qinval(). And in
iommu_resume(), we invoke iommu_flush_all() for safety.
Signed-off-by: Dexuan Cui <dexuan.cui@xxxxxxxxx>
---
xen/drivers/passthrough/vtd/iommu.c | 20 +++++++++++++++++++-
xen/drivers/passthrough/vtd/qinval.c | 7 ++++---
2 files changed, 23 insertions(+), 4 deletions(-)
diff -r f6a2bf60d49c -r 57b733f66531 xen/drivers/passthrough/vtd/iommu.c
--- a/xen/drivers/passthrough/vtd/iommu.c Tue Mar 31 11:51:56 2009 +0100
+++ b/xen/drivers/passthrough/vtd/iommu.c Tue Mar 31 11:54:12 2009 +0100
@@ -1953,16 +1953,34 @@ void iommu_resume(void)
{
struct acpi_drhd_unit *drhd;
struct iommu *iommu;
+ struct iommu_flush *flush;
u32 i;
if ( !vtd_enabled )
return;
+
+ /* Re-initialize the register-based flush functions.
+ * In iommu_flush_all(), we invoke iommu_flush_{context,iotlb}_global(),
+ * but at this point, on hosts that support QI(Queued Invalidation), QI
+ * hasn't been re-enabed yet, so for now let's use the register-based
+ * invalidation method before invoking init_vtd_hw().
+ */
+ if ( iommu_qinval )
+ {
+ for_each_drhd_unit ( drhd )
+ {
+ iommu = drhd->iommu;
+ flush = iommu_get_flush(iommu);
+ flush->context = flush_context_reg;
+ flush->iotlb = flush_iotlb_reg;
+ }
+ }
/* Not sure whether the flush operation is required to meet iommu
* specification. Note that BIOS also executes in S3 resume and iommu may
* be touched again, so let us do the flush operation for safety.
*/
- flush_all_cache();
+ iommu_flush_all();
if ( init_vtd_hw() != 0 && force_iommu )
panic("IOMMU setup failed, crash Xen for security purpose!\n");
diff -r f6a2bf60d49c -r 57b733f66531 xen/drivers/passthrough/vtd/qinval.c
--- a/xen/drivers/passthrough/vtd/qinval.c Tue Mar 31 11:51:56 2009 +0100
+++ b/xen/drivers/passthrough/vtd/qinval.c Tue Mar 31 11:54:12 2009 +0100
@@ -432,9 +432,10 @@ int enable_qinval(struct iommu *iommu)
"Cannot allocate memory for qi_ctrl->qinval_maddr\n");
return -ENOMEM;
}
- flush->context = flush_context_qi;
- flush->iotlb = flush_iotlb_qi;
- }
+ }
+
+ flush->context = flush_context_qi;
+ flush->iotlb = flush_iotlb_qi;
/* Setup Invalidation Queue Address(IQA) register with the
* address of the page we just allocated. QS field at
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|