From a8ea1e5fb64786065776491cec721b16d100171a Mon Sep 17 00:00:00 2001 From: Ferruh Yigit Date: Fri, 13 Oct 2017 03:46:44 +0100 Subject: [PATCH] igb_uio: fix unknown MSI symbols 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 --- lib/librte_eal/linuxapp/igb_uio/compat.h | 25 ++++++-- lib/librte_eal/linuxapp/igb_uio/igb_uio.c | 77 ++++++++++++++++++++--- 2 files changed, 91 insertions(+), 11 deletions(-) diff --git a/lib/librte_eal/linuxapp/igb_uio/compat.h b/lib/librte_eal/linuxapp/igb_uio/compat.h index 67a7ab3aff..30508f35c7 100644 --- a/lib/librte_eal/linuxapp/igb_uio/compat.h +++ b/lib/librte_eal/linuxapp/igb_uio/compat.h @@ -15,6 +15,21 @@ #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 + + diff --git a/lib/librte_eal/linuxapp/igb_uio/igb_uio.c b/lib/librte_eal/linuxapp/igb_uio/igb_uio.c index c8dd5f4d0b..0dda26c7a6 100644 --- a/lib/librte_eal/linuxapp/igb_uio/igb_uio.c +++ b/lib/librte_eal/linuxapp/igb_uio/igb_uio.c @@ -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 } -- 2.20.1