A urgent fix for the XEN related PCI/MSI changes:

XEN used a global variable to disable the masking of MSI interrupts as
   XEN handles that on the hypervisor side. This turned out to be a problem
   with VMD as the PCI devices behind a VMD bridge are not always handled
   by the hypervisor and then require masking by guest.
 
   To solve this the global variable was replaced by a interrupt domain
   specific flag, which is set by the generic XEN PCI/MSI domain, but not by
   VMD or any other domain in the system.
 
   So far, so good. But the implementation (and the reviewer) missed the
   fact, that accessing the domain flag cannot be done directly because
   there are at least two situations, where this fails. Legacy architectures
   are not providing interrupt domains at all. The new MSI parent domains do
   not require to have a domain info pointer. Both cases result in a
   unconditional NULL pointer derefence.
 
   The PCI/MSI code already has a function to query the MSI domain specific
   flag in a safe way, which handles all possible cases of PCI/MSI backends.
 
   So the fix it simply to replace the open coded checks by invoking the
   safe helper to query the flag.
 -----BEGIN PGP SIGNATURE-----
 
 iQJHBAABCgAxFiEEQp8+kY+LLUocC4bMphj1TA10mKEFAmfkUA4THHRnbHhAbGlu
 dXRyb25peC5kZQAKCRCmGPVMDXSYoVymD/4xvcTnjjBQgesBWtkZ/wyvOx+zAoZD
 s6ikEnYVzG6jjiob9SXrttJS/fZDuFujmntvq1lp+Lw1MbK/k9qyeKpMUkjVw4V5
 gHgPUZUkKapk2Jf3vYy23cb8CuRp9nANi7r//kzefN/pyEmfuqme3AYNJjusyEyn
 QfhLGE046GI2PLLS+4FKUjk+/aPEk/Pywy3moaSpDVd8Kmsus5GTmxt/AWcwGfcw
 00TSRKstpew+RVLBb7NvSar0D43vtvP/8If6qkIpEttVhB6/4zTREB1z6iPjUSf0
 2+90iubCdSm8wO+y0JDmA13cUct2XqW19M75imSLBIsJAlVtgWgOi2IJF787vDPJ
 3bN2HeScCbl8+0e4Uv+NOi2c906k43MtC4XTrIq0nZjAuRyF9FEtdK+IrcywxuKH
 nuaHtlseGWg97kU49yDTi1k+tRvIpmsibKM4pKZoUZKNMfE2soCFjzj40O7hTcKJ
 LaN/fcDdPGnn+GMPywwIWc7e6kOIYnCqakom/x7e+KWpqfujnM3KLiyOy9iys/oL
 xXfKnMbbmL0CSdUrC7EJn20KFRA2ovAJ+ouzJRkFhCdERCVidY29O3VrstacbevS
 zQKb302PbFraGHa/MiuzyF0BuWuM0T0d12+2wEoVJpN/GTAbgO2vVbk2gvHEReXJ
 eMDn02f5lF659w==
 =ZPMY
 -----END PGP SIGNATURE-----

Merge tag 'irq-urgent-2025-03-26' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull MSI irq fix from Thomas Gleixner:
 "An urgent fix for the XEN related PCI/MSI changes:

  XEN used a global variable to disable the masking of MSI interrupts as
  XEN handles that on the hypervisor side. This turned out to be a
  problem with VMD as the PCI devices behind a VMD bridge are not always
  handled by the hypervisor and then require masking by guest.

  To solve this the global variable was replaced by a interrupt domain
  specific flag, which is set by the generic XEN PCI/MSI domain, but not
  by VMD or any other domain in the system.

  So far, so good. But the implementation (and the reviewer) missed the
  fact, that accessing the domain flag cannot be done directly because
  there are at least two situations, where this fails.

  Legacy architectures are not providing interrupt domains at all. The
  new MSI parent domains do not require to have a domain info pointer.
  Both cases result in a unconditional NULL pointer derefence.

  The PCI/MSI code already has a function to query the MSI domain
  specific flag in a safe way, which handles all possible cases of
  PCI/MSI backends.

  So the fix it simply to replace the open coded checks by invoking the
  safe helper to query the flag"

* tag 'irq-urgent-2025-03-26' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  PCI/MSI: Handle the NOMASK flag correctly for all PCI/MSI backends
This commit is contained in:
Linus Torvalds 2025-03-26 13:20:22 -07:00
commit 87dc996d56

View File

@ -285,8 +285,6 @@ static void pci_msi_set_enable(struct pci_dev *dev, int enable)
static int msi_setup_msi_desc(struct pci_dev *dev, int nvec,
struct irq_affinity_desc *masks)
{
const struct irq_domain *d = dev_get_msi_domain(&dev->dev);
const struct msi_domain_info *info = d->host_data;
struct msi_desc desc;
u16 control;
@ -297,7 +295,7 @@ static int msi_setup_msi_desc(struct pci_dev *dev, int nvec,
/* Lies, damned lies, and MSIs */
if (dev->dev_flags & PCI_DEV_FLAGS_HAS_MSI_MASKING)
control |= PCI_MSI_FLAGS_MASKBIT;
if (info->flags & MSI_FLAG_NO_MASK)
if (pci_msi_domain_supports(dev, MSI_FLAG_NO_MASK, DENY_LEGACY))
control &= ~PCI_MSI_FLAGS_MASKBIT;
desc.nvec_used = nvec;
@ -604,20 +602,18 @@ static void __iomem *msix_map_region(struct pci_dev *dev,
*/
void msix_prepare_msi_desc(struct pci_dev *dev, struct msi_desc *desc)
{
const struct irq_domain *d = dev_get_msi_domain(&dev->dev);
const struct msi_domain_info *info = d->host_data;
desc->nvec_used = 1;
desc->pci.msi_attrib.is_msix = 1;
desc->pci.msi_attrib.is_64 = 1;
desc->pci.msi_attrib.default_irq = dev->irq;
desc->pci.mask_base = dev->msix_base;
desc->pci.msi_attrib.can_mask = !(info->flags & MSI_FLAG_NO_MASK) &&
!desc->pci.msi_attrib.is_virtual;
if (desc->pci.msi_attrib.can_mask) {
if (!pci_msi_domain_supports(dev, MSI_FLAG_NO_MASK, DENY_LEGACY) &&
!desc->pci.msi_attrib.is_virtual) {
void __iomem *addr = pci_msix_desc_addr(desc);
desc->pci.msi_attrib.can_mask = 1;
desc->pci.msix_ctrl = readl(addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
}
}
@ -715,8 +711,6 @@ static int msix_setup_interrupts(struct pci_dev *dev, struct msix_entry *entries
static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
int nvec, struct irq_affinity *affd)
{
const struct irq_domain *d = dev_get_msi_domain(&dev->dev);
const struct msi_domain_info *info = d->host_data;
int ret, tsize;
u16 control;
@ -747,7 +741,7 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,
/* Disable INTX */
pci_intx_for_msi(dev, 0);
if (!(info->flags & MSI_FLAG_NO_MASK)) {
if (!pci_msi_domain_supports(dev, MSI_FLAG_NO_MASK, DENY_LEGACY)) {
/*
* Ensure that all table entries are masked to prevent
* stale entries from firing in a crash kernel.