igb_uio: fix unknown MSI symbols
authorFerruh Yigit <ferruh.yigit@intel.com>
Fri, 13 Oct 2017 02:46:44 +0000 (03:46 +0100)
committerThomas Monjalon <thomas@monjalon.net>
Fri, 13 Oct 2017 13:50:13 +0000 (15:50 +0200)
This patch partially reverts the commit d196343a258e and adds some
functions from Markus' previous version of the patch [1].

igb_uio uses pci_msi_unmask_irq() and pci_msi_mask_irq() kernel APIs
when kernel version is >= 3.19 because these APIs are implemented in
this Linux kernel version.

But these APIs only exported beginning from Linux kernel 4.5, so before
this Linux kernel version igb_uio kernel module is not usable,
and giving following warnings:
"igb_uio: Unknown symbol pci_msi_unmask_irq"
"igb_uio: Unknown symbol pci_msi_mask_irq"

The support for these APIs increased to Linux kernel >= 4.5

For older version of Linux kernel unmask_msi_irq() and mask_msi_irq()
are used but these functions are not exported at all.
Instead of these functions switched back to previous implementation in
igb_uio for MSI-X, and for MSI used igbuio_msi_mask_irq() from [1].

[1]
http://dpdk.org/dev/patchwork/patch/28144/

Fixes: d196343a258e ("igb_uio: use kernel functions for masking MSI-X")

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
lib/librte_eal/linuxapp/igb_uio/compat.h
lib/librte_eal/linuxapp/igb_uio/igb_uio.c

index 67a7ab3..30508f3 100644 (file)
 #define HAVE_PTE_MASK_PAGE_IOMAP
 #endif
 
+#ifndef PCI_MSIX_ENTRY_SIZE
+#define PCI_MSIX_ENTRY_SIZE            16
+#define PCI_MSIX_ENTRY_VECTOR_CTRL     12
+#define PCI_MSIX_ENTRY_CTRL_MASKBIT    1
+#endif
+
+/*
+ * for kernels < 2.6.38 and backported patch that moves MSI-X entry definition
+ * to pci_regs.h Those kernels has PCI_MSIX_ENTRY_SIZE defined but not
+ * PCI_MSIX_ENTRY_CTRL_MASKBIT
+ */
+#ifndef PCI_MSIX_ENTRY_CTRL_MASKBIT
+#define PCI_MSIX_ENTRY_CTRL_MASKBIT    1
+#endif
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34) && \
        (!(defined(RHEL_RELEASE_CODE) && \
         RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(5, 9)))
@@ -110,10 +125,12 @@ static bool pci_check_and_mask_intx(struct pci_dev *pdev)
 #define HAVE_ALLOC_IRQ_VECTORS 1
 #endif
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
-#define HAVE_PCI_MSI_MASK_IRQ 1
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
+#define HAVE_MSI_LIST_IN_GENERIC_DEVICE 1
 #endif
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
-#define HAVE_IRQ_DATA 1
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
+#define HAVE_PCI_MSI_MASK_IRQ 1
 #endif
+
+
index c8dd5f4..0dda26c 100644 (file)
@@ -90,6 +90,74 @@ static const struct attribute_group dev_attr_grp = {
        .attrs = dev_attrs,
 };
 
+#ifndef HAVE_PCI_MSI_MASK_IRQ
+/*
+ * It masks the msix on/off of generating MSI-X messages.
+ */
+static void
+igbuio_msix_mask_irq(struct msi_desc *desc, s32 state)
+{
+       u32 mask_bits = desc->masked;
+       unsigned int offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+                                               PCI_MSIX_ENTRY_VECTOR_CTRL;
+
+       if (state != 0)
+               mask_bits &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
+       else
+               mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
+
+       if (mask_bits != desc->masked) {
+               writel(mask_bits, desc->mask_base + offset);
+               readl(desc->mask_base);
+               desc->masked = mask_bits;
+       }
+}
+
+/*
+ * It masks the msi on/off of generating MSI messages.
+ */
+static void
+igbuio_msi_mask_irq(struct pci_dev *pdev, struct msi_desc *desc, int32_t state)
+{
+       u32 mask_bits = desc->masked;
+       u32 offset = desc->irq - pdev->irq;
+       u32 mask = 1 << offset;
+       u32 flag = !!state << offset;
+
+       if (!desc->msi_attrib.maskbit)
+               return;
+
+       mask_bits &= ~mask;
+       mask_bits |= flag;
+
+       if (mask_bits != desc->masked) {
+               pci_write_config_dword(pdev, desc->mask_pos, mask_bits);
+               desc->masked = mask_bits;
+       }
+}
+
+static void
+igbuio_mask_irq(struct pci_dev *pdev, enum rte_intr_mode mode, s32 irq_state)
+{
+       struct msi_desc *desc;
+       struct list_head *msi_list;
+
+#ifdef HAVE_MSI_LIST_IN_GENERIC_DEVICE
+       msi_list = &pdev->dev.msi_list;
+#else
+       msi_list = &pdev->msi_list;
+#endif
+
+       if (mode == RTE_INTR_MODE_MSIX) {
+               list_for_each_entry(desc, msi_list, list)
+                       igbuio_msix_mask_irq(desc, irq_state);
+       } else if (mode == RTE_INTR_MODE_MSI) {
+               list_for_each_entry(desc, msi_list, list)
+                       igbuio_msi_mask_irq(pdev, desc, irq_state);
+       }
+}
+#endif
+
 /**
  * This is the irqcontrol callback to be registered to uio_info.
  * It can be used to disable/enable interrupt from user space processes.
@@ -109,10 +177,8 @@ igbuio_pci_irqcontrol(struct uio_info *info, s32 irq_state)
        struct rte_uio_pci_dev *udev = info->priv;
        struct pci_dev *pdev = udev->pdev;
 
-#ifdef HAVE_IRQ_DATA
+#ifdef HAVE_PCI_MSI_MASK_IRQ
        struct irq_data *irq = irq_get_irq_data(udev->info.irq);
-#else
-       unsigned int irq = udev->info.irq;
 #endif
 
        pci_cfg_access_lock(pdev);
@@ -124,10 +190,7 @@ igbuio_pci_irqcontrol(struct uio_info *info, s32 irq_state)
                else
                        pci_msi_mask_irq(irq);
 #else
-               if (irq_state == 1)
-                       unmask_msi_irq(irq);
-               else
-                       mask_msi_irq(irq);
+               igbuio_mask_irq(pdev, udev->mode, irq_state);
 #endif
        }