Skip to content

Commit

Permalink
PCI/MSI: Reject multi-MSI early
Browse files Browse the repository at this point in the history
When hierarchical MSI interrupt domains are enabled then there is no point
to do tons of work and detect the missing support for multi-MSI late in the
allocation path.

Just query the domain feature flags right away. The query function is going
to be used for other purposes later and has a mode argument which influences
the result:

  ALLOW_LEGACY returns true when:
     - there is no irq domain attached (legacy support)
     - there is a irq domain attached which has the feature flag set

  DENY_LEGACY returns only true when:
     - there is a irq domain attached which has the feature flag set

This allows to use the function universally without ifdeffery in the
calling code.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Link: https://lore.kernel.org/r/20221111122015.574339988@linutronix.de
  • Loading branch information
Thomas Gleixner committed Nov 17, 2022
1 parent bab65e4 commit d2a463b
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 0 deletions.
22 changes: 22 additions & 0 deletions drivers/pci/msi/irqdomain.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,28 @@ struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode,
}
EXPORT_SYMBOL_GPL(pci_msi_create_irq_domain);

/**
* pci_msi_domain_supports - Check for support of a particular feature flag
* @pdev: The PCI device to operate on
* @feature_mask: The feature mask to check for (full match)
* @mode: If ALLOW_LEGACY this grants the feature when there is no irq domain
* associated to the device. If DENY_LEGACY the lack of an irq domain
* makes the feature unsupported
*/
bool pci_msi_domain_supports(struct pci_dev *pdev, unsigned int feature_mask,
enum support_mode mode)
{
struct msi_domain_info *info;
struct irq_domain *domain;

domain = dev_get_msi_domain(&pdev->dev);

if (!domain || !irq_domain_is_hierarchy(domain))
return mode == ALLOW_LEGACY;
info = domain->host_data;
return (info->flags & feature_mask) == feature_mask;
}

/*
* Users of the generic MSI infrastructure expect a device to have a single ID,
* so with DMA aliases we have to pick the least-worst compromise. Devices with
Expand Down
4 changes: 4 additions & 0 deletions drivers/pci/msi/msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,10 @@ static int msi_capability_init(struct pci_dev *dev, int nvec,
struct msi_desc *entry;
int ret;

/* Reject multi-MSI early on irq domain enabled architectures */
if (nvec > 1 && !pci_msi_domain_supports(dev, MSI_FLAG_MULTI_PCI_MSI, ALLOW_LEGACY))
return 1;

/*
* Disable MSI during setup in the hardware, but mark it enabled
* so that setup code can evaluate it.
Expand Down
9 changes: 9 additions & 0 deletions drivers/pci/msi/msi.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ int __pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, int
void __pci_restore_msi_state(struct pci_dev *dev);
void __pci_restore_msix_state(struct pci_dev *dev);

/* irq_domain related functionality */

enum support_mode {
ALLOW_LEGACY,
DENY_LEGACY,
};

bool pci_msi_domain_supports(struct pci_dev *dev, unsigned int feature_mask, enum support_mode mode);

/* Legacy (!IRQDOMAIN) fallbacks */

#ifdef CONFIG_PCI_MSI_ARCH_FALLBACKS
Expand Down

0 comments on commit d2a463b

Please sign in to comment.