[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v2 5/5] x86/iommu: disable interrupts at shutdown
Add a new hook to inhibit interrupt generation by the IOMMU(s). Note the hook is currently only implemented for x86 IOMMUs. The purpose is to disable interrupt generation at shutdown so any kexec chained image finds the IOMMU(s) in a quiesced state. It would also prevent "Receive accept error" being raised as a result of non-disabled interrupts targeting offline CPUs. Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx> --- Changes since v1: - New in this version. --- xen/arch/x86/crash.c | 1 + xen/arch/x86/smp.c | 1 + xen/drivers/passthrough/amd/iommu.h | 1 + xen/drivers/passthrough/amd/iommu_init.c | 17 +++++++++++++++++ xen/drivers/passthrough/amd/pci_amd_iommu.c | 1 + xen/drivers/passthrough/iommu.c | 6 ++++++ xen/drivers/passthrough/vtd/iommu.c | 19 +++++++++++++++++++ xen/include/xen/iommu.h | 3 +++ 8 files changed, 49 insertions(+) diff --git a/xen/arch/x86/crash.c b/xen/arch/x86/crash.c index c946225c0b9b..a5feed298d1e 100644 --- a/xen/arch/x86/crash.c +++ b/xen/arch/x86/crash.c @@ -178,6 +178,7 @@ static void nmi_shootdown_cpus(void) disable_IO_APIC(); hpet_disable(); pci_disable_msi_all(); + iommu_quiesce(); } } diff --git a/xen/arch/x86/smp.c b/xen/arch/x86/smp.c index f58c8d3cafe1..06c0e84d40b3 100644 --- a/xen/arch/x86/smp.c +++ b/xen/arch/x86/smp.c @@ -377,6 +377,7 @@ void smp_send_stop(void) disable_IO_APIC(); hpet_disable(); pci_disable_msi_all(); + iommu_quiesce(); if ( num_online_cpus() > 1 ) { diff --git a/xen/drivers/passthrough/amd/iommu.h b/xen/drivers/passthrough/amd/iommu.h index c32e9e9a1602..00e81b4b2ab3 100644 --- a/xen/drivers/passthrough/amd/iommu.h +++ b/xen/drivers/passthrough/amd/iommu.h @@ -292,6 +292,7 @@ extern unsigned long *shared_intremap_inuse; void cf_check amd_iommu_resume(void); int __must_check cf_check amd_iommu_suspend(void); void cf_check amd_iommu_crash_shutdown(void); +void cf_check amd_iommu_quiesce(void); static inline u32 get_field_from_reg_u32(u32 reg_value, u32 mask, u32 shift) { diff --git a/xen/drivers/passthrough/amd/iommu_init.c b/xen/drivers/passthrough/amd/iommu_init.c index 302362502033..2e60aef151b0 100644 --- a/xen/drivers/passthrough/amd/iommu_init.c +++ b/xen/drivers/passthrough/amd/iommu_init.c @@ -1611,3 +1611,20 @@ void cf_check amd_iommu_resume(void) invalidate_all_domain_pages(); } } + +void cf_check amd_iommu_quiesce(void) +{ + struct amd_iommu *iommu; + + for_each_amd_iommu ( iommu ) + { + if ( iommu->ctrl.int_cap_xt_en ) + { + iommu->ctrl.int_cap_xt_en = false; + writeq(iommu->ctrl.raw, + iommu->mmio_base + IOMMU_CONTROL_MMIO_OFFSET); + } + else + amd_iommu_msi_enable(iommu, IOMMU_CONTROL_DISABLED); + } +} diff --git a/xen/drivers/passthrough/amd/pci_amd_iommu.c b/xen/drivers/passthrough/amd/pci_amd_iommu.c index f96f59440bcc..d00697edb3a2 100644 --- a/xen/drivers/passthrough/amd/pci_amd_iommu.c +++ b/xen/drivers/passthrough/amd/pci_amd_iommu.c @@ -791,6 +791,7 @@ static const struct iommu_ops __initconst_cf_clobber _iommu_ops = { .crash_shutdown = amd_iommu_crash_shutdown, .get_reserved_device_memory = amd_iommu_get_reserved_device_memory, .dump_page_tables = amd_dump_page_tables, + .quiesce = amd_iommu_quiesce, }; static const struct iommu_init_ops __initconstrel _iommu_init_ops = { diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c index 9e74a1fc72fa..35c08ee0612c 100644 --- a/xen/drivers/passthrough/iommu.c +++ b/xen/drivers/passthrough/iommu.c @@ -663,6 +663,12 @@ void iommu_crash_shutdown(void) #endif } +void iommu_quiesce(void) +{ + if ( iommu_enabled ) + iommu_vcall(iommu_get_ops(), quiesce); +} + int iommu_get_reserved_device_memory(iommu_grdm_t *func, void *ctxt) { const struct iommu_ops *ops; diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c index 9d7a9977a6a6..a1927d9f126d 100644 --- a/xen/drivers/passthrough/vtd/iommu.c +++ b/xen/drivers/passthrough/vtd/iommu.c @@ -3207,6 +3207,24 @@ static int cf_check intel_iommu_quarantine_init(struct pci_dev *pdev, return rc; } +static void cf_check vtd_quiesce(void) +{ + const struct acpi_drhd_unit *drhd; + + for_each_drhd_unit ( drhd ) + { + const struct vtd_iommu *iommu = drhd->iommu; + uint32_t sts = dmar_readl(iommu->reg, DMAR_FECTL_REG); + + /* + * Open code dma_msi_mask() to avoid taking the spinlock which could + * deadlock if called from crash context. + */ + sts |= DMA_FECTL_IM; + dmar_writel(iommu->reg, DMAR_FECTL_REG, sts); + } +} + static const struct iommu_ops __initconst_cf_clobber vtd_ops = { .page_sizes = PAGE_SIZE_4K, .init = intel_iommu_domain_init, @@ -3236,6 +3254,7 @@ static const struct iommu_ops __initconst_cf_clobber vtd_ops = { .iotlb_flush = iommu_flush_iotlb, .get_reserved_device_memory = intel_iommu_get_reserved_device_memory, .dump_page_tables = vtd_dump_page_tables, + .quiesce = vtd_quiesce, }; const struct iommu_init_ops __initconstrel intel_iommu_init_ops = { diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h index b928c67e1995..77a514019cc6 100644 --- a/xen/include/xen/iommu.h +++ b/xen/include/xen/iommu.h @@ -314,6 +314,8 @@ struct iommu_ops { */ int (*dt_xlate)(device_t *dev, const struct dt_phandle_args *args); #endif + /* Inhibit all interrupt generation, to be used at shutdown. */ + void (*quiesce)(void); }; /* @@ -404,6 +406,7 @@ static inline int iommu_do_domctl(struct xen_domctl *domctl, struct domain *d, int __must_check iommu_suspend(void); void iommu_resume(void); void iommu_crash_shutdown(void); +void iommu_quiesce(void); int iommu_get_reserved_device_memory(iommu_grdm_t *func, void *ctxt); int iommu_quarantine_dev_init(device_t *dev); -- 2.46.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |