@@ -224,4 +224,12 @@ static inline struct pci_dev *pcie_find_root_port(struct pci_dev *dev)
#endif/* <4.9.0 but not >= 3.12.69, 4.4.37, 4.8.13 */
+#ifndef PCI_IRQ_LEGACY
+#define PCI_IRQ_LEGACY (1 << 0) /* Allow legacy interrupts */
+#define PCI_IRQ_MSI (1 << 1) /* Allow MSI interrupts */
+#define PCI_IRQ_MSIX (1 << 2) /* Allow MSI-X interrupts */
+#define PCI_IRQ_ALL_TYPES \
+ (PCI_IRQ_LEGACY | PCI_IRQ_MSI | PCI_IRQ_MSIX)
+#endif
+
#endif /* _BACKPORT_LINUX_PCI_H */
@@ -148,25 +148,48 @@ EXPORT_SYMBOL_GPL(cdc_parse_cdc_header);
#ifdef CONFIG_PCI
#ifdef CONFIG_PCI_MSI
+
+/**
+ * pci_alloc_irq_vectors - allocate multiple IRQs for a device
+ * @dev: PCI device to operate on
+ * @min_vecs: minimum number of vectors required (must be >= 1)
+ * @max_vecs: maximum (desired) number of vectors
+ * @flags: flags or quirks for the allocation
+ *
+ * Allocate up to @max_vecs interrupt vectors for @dev, using MSI-X or MSI
+ * vectors if available, and fall back to a single legacy vector
+ * if neither is available. Return the number of vectors allocated,
+ * (which might be smaller than @max_vecs) if successful, or a negative
+ * error code on error. If less than @min_vecs interrupt vectors are
+ * available for @dev the function will fail with -ENOSPC.
+ *
+ * To get the Linux IRQ number used for a vector that can be passed to
+ * request_irq() use the pci_irq_vector() helper.
+ */
int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
unsigned int max_vecs, unsigned int flags)
{
- int res;
- int msi_nvect = max_vecs;
+ int vecs = -ENOSPC;
- if (max_vecs < min_vecs)
- return -ERANGE;
+ if (flags & PCI_IRQ_MSIX) {
+ vecs = pci_enable_msix_range(dev, NULL, min_vecs, max_vecs);
+ if (vecs > 0)
+ return vecs;
+ }
+
+ if (flags & PCI_IRQ_MSI) {
+ vecs = pci_enable_msi_range(dev, min_vecs, max_vecs);
+ if (vecs > 0)
+ return vecs;
+ }
-#if LINUX_VERSION_IS_LESS(3,15,0)
- res = pci_enable_msi_block(dev, msi_nvect);
- if (res == 0) {
- return msi_nvect;
+ /* use legacy irq if allowed */
+ if ((flags & PCI_IRQ_LEGACY) && min_vecs == 1) {
+ pci_intx(dev, 1);
+ return 1;
}
-#else
- res = pci_enable_msi_range(dev, msi_nvect, msi_nvect);
- return msi_nvect;
-#endif /*LINUX_VERSION_IS_LESS(3,15,0)*/
- return -ENOSPC;
+
+ return vecs;
}
EXPORT_SYMBOL_GPL(pci_alloc_irq_vectors);
#endif /* CONFIG_PCI_MSI */
This copies the pci_alloc_irq_vectors() function from kernel 4.9 and replaces the __pci_enable_msi{x}_range() calls with calls to pci_enable_msi{x}_range(), these were backported to kernel versions < 3.14, so no need to handle the older kernels specially here. This also adds support for MSIx IRQs and adds the PCI_IRQ_* defines. Fixes: 162a6b312f1b ("add support for pci_alloc_irq_vectors") Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> Cc: Omer Dagan <omer.dagan@tandemg.com> --- backport/backport-include/linux/pci.h | 8 ++++++ backport/compat/backport-4.8.c | 49 +++++++++++++++++++++++++---------- 2 files changed, 44 insertions(+), 13 deletions(-)