[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen staging-4.18] x86/pci: disable MSI(-X) on all devices at shutdown
commit 9f4c92d70e3aff831c34e324dabf209bf7b6ab4e Author: Roger Pau Monné <roger.pau@xxxxxxxxxx> AuthorDate: Mon Feb 17 13:32:52 2025 +0100 Commit: Jan Beulich <jbeulich@xxxxxxxx> CommitDate: Mon Feb 17 13:32:52 2025 +0100 x86/pci: disable MSI(-X) on all devices at shutdown Attempt to disable MSI(-X) capabilities on all PCI devices know by Xen at shutdown. Doing such disabling should facilitate kexec chained kernel from booting more reliably, as device MSI(-X) interrupt generation should be quiesced. Only attempt to disable MSI(-X) on all devices in the crash context if the PCI lock is not taken, otherwise the PCI device list could be in an inconsistent state. This requires introducing a new pcidevs_trylock() helper to check whether the lock is currently taken. Disabling MSI(-X) should 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> Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx> master commit: 7ab6951981231b4c576a3588248c303001272588 master date: 2025-02-12 15:56:07 +0100 --- xen/arch/x86/crash.c | 10 ++++++++++ xen/arch/x86/include/asm/msi.h | 1 + xen/arch/x86/msi.c | 18 ++++++++++++++++++ xen/arch/x86/smp.c | 1 + xen/drivers/passthrough/pci.c | 42 ++++++++++++++++++++++++++++++++++++++++++ xen/include/xen/pci.h | 12 ++++++++++++ 6 files changed, 84 insertions(+) diff --git a/xen/arch/x86/crash.c b/xen/arch/x86/crash.c index a789416ca3..22b1121d7a 100644 --- a/xen/arch/x86/crash.c +++ b/xen/arch/x86/crash.c @@ -175,6 +175,16 @@ static void nmi_shootdown_cpus(void) */ x2apic_enabled = (current_local_apic_mode() == APIC_MODE_X2APIC); + if ( pcidevs_trylock() ) + { + /* + * Assume the PCI device list to be in a consistent state if the + * lock is not held when the crash happened. + */ + pci_disable_msi_all(); + pcidevs_unlock(); + } + disable_IO_APIC(); hpet_disable(); } diff --git a/xen/arch/x86/include/asm/msi.h b/xen/arch/x86/include/asm/msi.h index a53ade95c9..5f5b499c82 100644 --- a/xen/arch/x86/include/asm/msi.h +++ b/xen/arch/x86/include/asm/msi.h @@ -85,6 +85,7 @@ extern int pci_enable_msi(struct msi_info *msi, struct msi_desc **desc); extern void pci_disable_msi(struct msi_desc *desc); extern int pci_prepare_msix(u16 seg, u8 bus, u8 devfn, bool off); extern void pci_cleanup_msi(struct pci_dev *pdev); +extern void pci_disable_msi_all(void); extern int setup_msi_irq(struct irq_desc *, struct msi_desc *); extern int __setup_msi_irq(struct irq_desc *, struct msi_desc *, const struct hw_interrupt_type *); diff --git a/xen/arch/x86/msi.c b/xen/arch/x86/msi.c index 3eaeffd1e0..850995730c 100644 --- a/xen/arch/x86/msi.c +++ b/xen/arch/x86/msi.c @@ -1193,6 +1193,24 @@ void pci_cleanup_msi(struct pci_dev *pdev) msi_free_irqs(pdev); } +static int cf_check disable_msi(struct pci_dev *pdev, void *arg) +{ + msi_set_enable(pdev, 0); + msix_set_enable(pdev, 0); + + return 0; +} + +/* Disable MSI and/or MSI-X on all devices known by Xen. */ +void pci_disable_msi_all(void) +{ + int rc = pci_iterate_devices(disable_msi, NULL); + + if ( rc ) + printk(XENLOG_ERR + "Failed to disable MSI(-X) on some devices: %d\n", rc); +} + int pci_reset_msix_state(struct pci_dev *pdev) { unsigned int pos = pci_find_cap_offset(pdev->sbdf, PCI_CAP_ID_MSIX); diff --git a/xen/arch/x86/smp.c b/xen/arch/x86/smp.c index bf095ea6c6..3b79436b31 100644 --- a/xen/arch/x86/smp.c +++ b/xen/arch/x86/smp.c @@ -372,6 +372,7 @@ void smp_send_stop(void) smp_call_function(stop_this_cpu, &stop_aps, 0); local_irq_disable(); + pci_disable_msi_all(); disable_IO_APIC(); hpet_disable(); diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c index 0852e4f172..b7afdccf23 100644 --- a/xen/drivers/passthrough/pci.c +++ b/xen/drivers/passthrough/pci.c @@ -68,6 +68,11 @@ bool pcidevs_locked(void) return !!spin_is_locked(&_pcidevs_lock); } +bool pcidevs_trylock_unsafe(void) +{ + return spin_trylock_recursive(&_pcidevs_lock); +} + static RADIX_TREE(pci_segments); static inline struct pci_seg *get_pseg(u16 seg) @@ -1691,6 +1696,43 @@ int iommu_do_pci_domctl( return ret; } +struct segment_iter { + int (*handler)(struct pci_dev *pdev, void *arg); + void *arg; + int rc; +}; + +static int cf_check iterate_all(struct pci_seg *pseg, void *arg) +{ + struct segment_iter *iter = arg; + struct pci_dev *pdev; + + list_for_each_entry ( pdev, &pseg->alldevs_list, alldevs_list ) + { + int rc = iter->handler(pdev, iter->arg); + + if ( !iter->rc ) + iter->rc = rc; + } + + return 0; +} + +/* + * Iterate without locking or preemption over all PCI devices known by Xen. + * Can be called with interrupts disabled. + */ +int pci_iterate_devices(int (*handler)(struct pci_dev *pdev, void *arg), + void *arg) +{ + struct segment_iter iter = { + .handler = handler, + .arg = arg, + }; + + return pci_segments_iterate(iterate_all, &iter) ?: iter.rc; +} + /* * Local variables: * mode: C diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h index a71bed36be..a880aae5eb 100644 --- a/xen/include/xen/pci.h +++ b/xen/include/xen/pci.h @@ -163,6 +163,11 @@ static always_inline void pcidevs_lock(void) } void pcidevs_unlock(void); bool __must_check pcidevs_locked(void); +bool pcidevs_trylock_unsafe(void); +static always_inline bool pcidevs_trylock(void) +{ + return lock_evaluate_nospec(pcidevs_trylock_unsafe()); +} bool pci_known_segment(u16 seg); bool pci_device_detect(u16 seg, u8 bus, u8 dev, u8 func); @@ -185,6 +190,13 @@ struct pci_dev *pci_get_pdev(const struct domain *d, pci_sbdf_t sbdf); struct pci_dev *pci_get_real_pdev(pci_sbdf_t sbdf); void pci_check_disable_device(u16 seg, u8 bus, u8 devfn); +/* + * Iterate without locking or preemption over all PCI devices known by Xen. + * Can be called with interrupts disabled. + */ +int pci_iterate_devices(int (*handler)(struct pci_dev *pdev, void *arg), + void *arg); + uint8_t pci_conf_read8(pci_sbdf_t sbdf, unsigned int reg); uint16_t pci_conf_read16(pci_sbdf_t sbdf, unsigned int reg); uint32_t pci_conf_read32(pci_sbdf_t sbdf, unsigned int reg); -- generated by git-patchbot for /home/xen/git/xen.git#staging-4.18
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |