+// SPDX-License-Identifier: GPL-2.0
/*-
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
- *
- * Contact Information:
- * Intel Corporation
+ * Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
static char *intr_mode;
static enum rte_intr_mode igbuio_intr_mode_preferred = RTE_INTR_MODE_MSIX;
-
/* sriov sysfs */
static ssize_t
show_max_vfs(struct device *dev, struct device_attribute *attr,
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 (state != 0)
+ mask_bits &= ~mask;
+ else
+ mask_bits |= mask;
if (mask_bits != desc->masked) {
pci_write_config_dword(pdev, desc->mask_pos, mask_bits);
* If yes, disable it here and will be enable later.
*/
static irqreturn_t
-igbuio_pci_irqhandler(int irq, struct uio_info *info)
+igbuio_pci_irqhandler(int irq, void *dev_id)
{
- struct rte_uio_pci_dev *udev = info->priv;
+ struct rte_uio_pci_dev *udev = (struct rte_uio_pci_dev *)dev_id;
+ struct uio_info *info = &udev->info;
/* Legacy mode need to mask in hardware */
if (udev->mode == RTE_INTR_MODE_LEGACY &&
!pci_check_and_mask_intx(udev->pdev))
return IRQ_NONE;
+ uio_event_notify(info);
+
/* Message signal mode, no share IRQ and automasked */
return IRQ_HANDLED;
}
-/**
- * This gets called while opening uio device file.
- */
-static int
-igbuio_pci_open(struct uio_info *info, struct inode *inode)
-{
- struct rte_uio_pci_dev *udev = info->priv;
- struct pci_dev *dev = udev->pdev;
-
- pci_reset_function(dev);
-
- /* set bus master, which was cleared by the reset function */
- pci_set_master(dev);
-
- return 0;
-}
-
-static int
-igbuio_pci_release(struct uio_info *info, struct inode *inode)
-{
- struct rte_uio_pci_dev *udev = info->priv;
- struct pci_dev *dev = udev->pdev;
-
- /* stop the device from further DMA */
- pci_clear_master(dev);
-
- pci_reset_function(dev);
-
- return 0;
-}
-
-/* Remap pci resources described by bar #pci_bar in uio resource n. */
-static int
-igbuio_pci_setup_iomem(struct pci_dev *dev, struct uio_info *info,
- int n, int pci_bar, const char *name)
-{
- unsigned long addr, len;
- void *internal_addr;
-
- if (n >= ARRAY_SIZE(info->mem))
- return -EINVAL;
-
- addr = pci_resource_start(dev, pci_bar);
- len = pci_resource_len(dev, pci_bar);
- if (addr == 0 || len == 0)
- return -1;
- internal_addr = ioremap(addr, len);
- if (internal_addr == NULL)
- return -1;
- info->mem[n].name = name;
- info->mem[n].addr = addr;
- info->mem[n].internal_addr = internal_addr;
- info->mem[n].size = len;
- info->mem[n].memtype = UIO_MEM_PHYS;
- return 0;
-}
-
-/* Get pci port io resources described by bar #pci_bar in uio resource n. */
-static int
-igbuio_pci_setup_ioport(struct pci_dev *dev, struct uio_info *info,
- int n, int pci_bar, const char *name)
-{
- unsigned long addr, len;
-
- if (n >= ARRAY_SIZE(info->port))
- return -EINVAL;
-
- addr = pci_resource_start(dev, pci_bar);
- len = pci_resource_len(dev, pci_bar);
- if (addr == 0 || len == 0)
- return -EINVAL;
-
- info->port[n].name = name;
- info->port[n].start = addr;
- info->port[n].size = len;
- info->port[n].porttype = UIO_PORT_X86;
-
- return 0;
-}
-
-/* Unmap previously ioremap'd resources */
-static void
-igbuio_pci_release_iomem(struct uio_info *info)
-{
- int i;
-
- for (i = 0; i < MAX_UIO_MAPS; i++) {
- if (info->mem[i].internal_addr)
- iounmap(info->mem[i].internal_addr);
- }
-}
-
static int
igbuio_pci_enable_interrupts(struct rte_uio_pci_dev *udev)
{
break;
}
#endif
+
/* fall back to MSI */
case RTE_INTR_MODE_MSI:
#ifndef HAVE_ALLOC_IRQ_VECTORS
default:
dev_err(&udev->pdev->dev, "invalid IRQ mode %u",
igbuio_intr_mode_preferred);
+ udev->info.irq = UIO_IRQ_NONE;
err = -EINVAL;
}
+ if (udev->info.irq != UIO_IRQ_NONE)
+ err = request_irq(udev->info.irq, igbuio_pci_irqhandler,
+ udev->info.irq_flags, udev->info.name,
+ udev);
+ dev_info(&udev->pdev->dev, "uio device registered with irq %lx\n",
+ udev->info.irq);
+
return err;
}
static void
igbuio_pci_disable_interrupts(struct rte_uio_pci_dev *udev)
{
+ if (udev->info.irq) {
+ free_irq(udev->info.irq, udev);
+ udev->info.irq = 0;
+ }
+
#ifndef HAVE_ALLOC_IRQ_VECTORS
if (udev->mode == RTE_INTR_MODE_MSIX)
pci_disable_msix(udev->pdev);
#endif
}
+
+/**
+ * This gets called while opening uio device file.
+ */
+static int
+igbuio_pci_open(struct uio_info *info, struct inode *inode)
+{
+ struct rte_uio_pci_dev *udev = info->priv;
+ struct pci_dev *dev = udev->pdev;
+ int err;
+
+ /* set bus master, which was cleared by the reset function */
+ pci_set_master(dev);
+
+ /* enable interrupts */
+ err = igbuio_pci_enable_interrupts(udev);
+ if (err) {
+ dev_err(&dev->dev, "Enable interrupt fails\n");
+ return err;
+ }
+ return 0;
+}
+
+static int
+igbuio_pci_release(struct uio_info *info, struct inode *inode)
+{
+ struct rte_uio_pci_dev *udev = info->priv;
+ struct pci_dev *dev = udev->pdev;
+
+ /* disable interrupts */
+ igbuio_pci_disable_interrupts(udev);
+
+ /* stop the device from further DMA */
+ pci_clear_master(dev);
+
+ return 0;
+}
+
+/* Remap pci resources described by bar #pci_bar in uio resource n. */
+static int
+igbuio_pci_setup_iomem(struct pci_dev *dev, struct uio_info *info,
+ int n, int pci_bar, const char *name)
+{
+ unsigned long addr, len;
+ void *internal_addr;
+
+ if (n >= ARRAY_SIZE(info->mem))
+ return -EINVAL;
+
+ addr = pci_resource_start(dev, pci_bar);
+ len = pci_resource_len(dev, pci_bar);
+ if (addr == 0 || len == 0)
+ return -1;
+ internal_addr = ioremap(addr, len);
+ if (internal_addr == NULL)
+ return -1;
+ info->mem[n].name = name;
+ info->mem[n].addr = addr;
+ info->mem[n].internal_addr = internal_addr;
+ info->mem[n].size = len;
+ info->mem[n].memtype = UIO_MEM_PHYS;
+ return 0;
+}
+
+/* Get pci port io resources described by bar #pci_bar in uio resource n. */
+static int
+igbuio_pci_setup_ioport(struct pci_dev *dev, struct uio_info *info,
+ int n, int pci_bar, const char *name)
+{
+ unsigned long addr, len;
+
+ if (n >= ARRAY_SIZE(info->port))
+ return -EINVAL;
+
+ addr = pci_resource_start(dev, pci_bar);
+ len = pci_resource_len(dev, pci_bar);
+ if (addr == 0 || len == 0)
+ return -EINVAL;
+
+ info->port[n].name = name;
+ info->port[n].start = addr;
+ info->port[n].size = len;
+ info->port[n].porttype = UIO_PORT_X86;
+
+ return 0;
+}
+
+/* Unmap previously ioremap'd resources */
+static void
+igbuio_pci_release_iomem(struct uio_info *info)
+{
+ int i;
+
+ for (i = 0; i < MAX_UIO_MAPS; i++) {
+ if (info->mem[i].internal_addr)
+ iounmap(info->mem[i].internal_addr);
+ }
+}
+
static int
igbuio_setup_bars(struct pci_dev *dev, struct uio_info *info)
{
/* fill uio infos */
udev->info.name = "igb_uio";
udev->info.version = "0.1";
- udev->info.handler = igbuio_pci_irqhandler;
udev->info.irqcontrol = igbuio_pci_irqcontrol;
udev->info.open = igbuio_pci_open;
udev->info.release = igbuio_pci_release;
udev->info.priv = udev;
udev->pdev = dev;
- err = igbuio_pci_enable_interrupts(udev);
- if (err != 0)
- goto fail_release_iomem;
-
err = sysfs_create_group(&dev->dev.kobj, &dev_attr_grp);
if (err != 0)
- goto fail_disable_interrupts;
+ goto fail_release_iomem;
/* register uio driver */
err = uio_register_device(&dev->dev, &udev->info);
pci_set_drvdata(dev, udev);
- dev_info(&dev->dev, "uio device registered with irq %lx\n",
- udev->info.irq);
-
/*
* Doing a harmless dma mapping for attaching the device to
* the iommu identity mapping if kernel boots with iommu=pt.
fail_remove_group:
sysfs_remove_group(&dev->dev.kobj, &dev_attr_grp);
-fail_disable_interrupts:
- igbuio_pci_disable_interrupts(udev);
fail_release_iomem:
igbuio_pci_release_iomem(&udev->info);
pci_disable_device(dev);
sysfs_remove_group(&dev->dev.kobj, &dev_attr_grp);
uio_unregister_device(&udev->info);
- igbuio_pci_disable_interrupts(udev);
igbuio_pci_release_iomem(&udev->info);
pci_disable_device(dev);
pci_set_drvdata(dev, NULL);