1a551c94aSIdo Barnea/*-
2a551c94aSIdo Barnea * GPL LICENSE SUMMARY
3a551c94aSIdo Barnea *
4a551c94aSIdo Barnea *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5a551c94aSIdo Barnea *
6a551c94aSIdo Barnea *   This program is free software; you can redistribute it and/or modify
7a551c94aSIdo Barnea *   it under the terms of version 2 of the GNU General Public License as
8a551c94aSIdo Barnea *   published by the Free Software Foundation.
9a551c94aSIdo Barnea *
10a551c94aSIdo Barnea *   This program is distributed in the hope that it will be useful, but
11a551c94aSIdo Barnea *   WITHOUT ANY WARRANTY; without even the implied warranty of
13a551c94aSIdo Barnea *   General Public License for more details.
14a551c94aSIdo Barnea *
15a551c94aSIdo Barnea *   You should have received a copy of the GNU General Public License
16a551c94aSIdo Barnea *   along with this program; if not, write to the Free Software
17a551c94aSIdo Barnea *   Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18a551c94aSIdo Barnea *   The full GNU General Public License is included in this distribution
19a551c94aSIdo Barnea *   in the file called LICENSE.GPL.
20a551c94aSIdo Barnea *
21a551c94aSIdo Barnea *   Contact Information:
22a551c94aSIdo Barnea *   Intel Corporation
23a551c94aSIdo Barnea */
24a551c94aSIdo Barnea
25a551c94aSIdo Barnea#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26a551c94aSIdo Barnea
27a551c94aSIdo Barnea#include <linux/device.h>
28a551c94aSIdo Barnea#include <linux/module.h>
29a551c94aSIdo Barnea#include <linux/pci.h>
30a551c94aSIdo Barnea#include <linux/uio_driver.h>
31a551c94aSIdo Barnea#include <linux/io.h>
32a551c94aSIdo Barnea#include <linux/msi.h>
33a551c94aSIdo Barnea#include <linux/version.h>
34a551c94aSIdo Barnea#include <linux/slab.h>
35a551c94aSIdo Barnea
36a551c94aSIdo Barnea#ifdef CONFIG_XEN_DOM0
37a551c94aSIdo Barnea#include <xen/xen.h>
38a551c94aSIdo Barnea#endif
39a551c94aSIdo Barnea#include <rte_pci_dev_features.h>
40a551c94aSIdo Barnea
41a551c94aSIdo Barnea#include "compat.h"
42a551c94aSIdo Barnea
43a551c94aSIdo Barnea/**
44a551c94aSIdo Barnea * A structure describing the private information for a uio device.
45a551c94aSIdo Barnea */
46a551c94aSIdo Barneastruct rte_uio_pci_dev {
47a551c94aSIdo Barnea	struct uio_info info;
48a551c94aSIdo Barnea	struct pci_dev *pdev;
49a551c94aSIdo Barnea	enum rte_intr_mode mode;
50a551c94aSIdo Barnea};
51a551c94aSIdo Barnea
52a551c94aSIdo Barneastatic char *intr_mode;
53a551c94aSIdo Barneastatic enum rte_intr_mode igbuio_intr_mode_preferred = RTE_INTR_MODE_MSIX;
54a551c94aSIdo Barnea
55a551c94aSIdo Barnea/* sriov sysfs */
56a551c94aSIdo Barneastatic ssize_t
57a551c94aSIdo Barneashow_max_vfs(struct device *dev, struct device_attribute *attr,
58a551c94aSIdo Barnea	     char *buf)
59a551c94aSIdo Barnea{
60a551c94aSIdo Barnea	return snprintf(buf, 10, "%u\n", dev_num_vf(dev));
61a551c94aSIdo Barnea}
62a551c94aSIdo Barnea
63a551c94aSIdo Barneastatic ssize_t
64a551c94aSIdo Barneastore_max_vfs(struct device *dev, struct device_attribute *attr,
65a551c94aSIdo Barnea	      const char *buf, size_t count)
66a551c94aSIdo Barnea{
67a551c94aSIdo Barnea	int err = 0;
68a551c94aSIdo Barnea	unsigned long max_vfs;
69a551c94aSIdo Barnea	struct pci_dev *pdev = to_pci_dev(dev);
70a551c94aSIdo Barnea
71a551c94aSIdo Barnea	if (0 != kstrtoul(buf, 0, &max_vfs))
72a551c94aSIdo Barnea		return -EINVAL;
73a551c94aSIdo Barnea
74a551c94aSIdo Barnea	if (0 == max_vfs)
75a551c94aSIdo Barnea		pci_disable_sriov(pdev);
76a551c94aSIdo Barnea	else if (0 == pci_num_vf(pdev))
77a551c94aSIdo Barnea		err = pci_enable_sriov(pdev, max_vfs);
78a551c94aSIdo Barnea	else /* do nothing if change max_vfs number */
79a551c94aSIdo Barnea		err = -EINVAL;
80a551c94aSIdo Barnea
81a551c94aSIdo Barnea	return err ? err : count;
82a551c94aSIdo Barnea}
83a551c94aSIdo Barnea
84a551c94aSIdo Barneastatic DEVICE_ATTR(max_vfs, S_IRUGO | S_IWUSR, show_max_vfs, store_max_vfs);
85a551c94aSIdo Barnea
86a551c94aSIdo Barneastatic struct attribute *dev_attrs[] = {
87a551c94aSIdo Barnea	&dev_attr_max_vfs.attr,
88a551c94aSIdo Barnea	NULL,
89a551c94aSIdo Barnea};
90a551c94aSIdo Barnea
91a551c94aSIdo Barneastatic const struct attribute_group dev_attr_grp = {
92a551c94aSIdo Barnea	.attrs = dev_attrs,
93a551c94aSIdo Barnea};
94a551c94aSIdo Barnea/*
95a551c94aSIdo Barnea * It masks the msix on/off of generating MSI-X messages.
96a551c94aSIdo Barnea */
97a551c94aSIdo Barneastatic void
98a551c94aSIdo Barneaigbuio_msix_mask_irq(struct msi_desc *desc, int32_t state)
99a551c94aSIdo Barnea{
100a551c94aSIdo Barnea	u32 mask_bits = desc->masked;
101a551c94aSIdo Barnea	unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
102a551c94aSIdo Barnea						PCI_MSIX_ENTRY_VECTOR_CTRL;
103a551c94aSIdo Barnea
104a551c94aSIdo Barnea	if (state != 0)
105a551c94aSIdo Barnea		mask_bits &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
106a551c94aSIdo Barnea	else
107a551c94aSIdo Barnea		mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
108a551c94aSIdo Barnea
109a551c94aSIdo Barnea	if (mask_bits != desc->masked) {
110a551c94aSIdo Barnea		writel(mask_bits, desc->mask_base + offset);
111a551c94aSIdo Barnea		readl(desc->mask_base);
112a551c94aSIdo Barnea		desc->masked = mask_bits;
113a551c94aSIdo Barnea	}
114a551c94aSIdo Barnea}
115a551c94aSIdo Barnea
116a551c94aSIdo Barnea/**
117a551c94aSIdo Barnea * This is the irqcontrol callback to be registered to uio_info.
118a551c94aSIdo Barnea * It can be used to disable/enable interrupt from user space processes.
119a551c94aSIdo Barnea *
120a551c94aSIdo Barnea * @param info
121a551c94aSIdo Barnea *  pointer to uio_info.
122a551c94aSIdo Barnea * @param irq_state
123a551c94aSIdo Barnea *  state value. 1 to enable interrupt, 0 to disable interrupt.
124a551c94aSIdo Barnea *
125a551c94aSIdo Barnea * @return
126a551c94aSIdo Barnea *  - On success, 0.
127a551c94aSIdo Barnea *  - On failure, a negative value.
128a551c94aSIdo Barnea */
129a551c94aSIdo Barneastatic int
130a551c94aSIdo Barneaigbuio_pci_irqcontrol(struct uio_info *info, s32 irq_state)
131a551c94aSIdo Barnea{
132a551c94aSIdo Barnea	struct rte_uio_pci_dev *udev = info->priv;
133a551c94aSIdo Barnea	struct pci_dev *pdev = udev->pdev;
134a551c94aSIdo Barnea
135a551c94aSIdo Barnea	pci_cfg_access_lock(pdev);
136a551c94aSIdo Barnea	if (udev->mode == RTE_INTR_MODE_LEGACY)
137a551c94aSIdo Barnea		pci_intx(pdev, !!irq_state);
138a551c94aSIdo Barnea
139a551c94aSIdo Barnea	else if (udev->mode == RTE_INTR_MODE_MSIX) {
140a551c94aSIdo Barnea		struct msi_desc *desc;
141a551c94aSIdo Barnea
142a551c94aSIdo Barnea#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0))
143a551c94aSIdo Barnea		list_for_each_entry(desc, &pdev->msi_list, list)
144a551c94aSIdo Barnea			igbuio_msix_mask_irq(desc, irq_state);
145a551c94aSIdo Barnea#else
146a551c94aSIdo Barnea		list_for_each_entry(desc, &pdev->dev.msi_list, list)
147a551c94aSIdo Barnea			igbuio_msix_mask_irq(desc, irq_state);
148a551c94aSIdo Barnea#endif
149a551c94aSIdo Barnea	}
150a551c94aSIdo Barnea	pci_cfg_access_unlock(pdev);
151a551c94aSIdo Barnea
152a551c94aSIdo Barnea	return 0;
153a551c94aSIdo Barnea}
154a551c94aSIdo Barnea
155a551c94aSIdo Barnea/**
156a551c94aSIdo Barnea * This is interrupt handler which will check if the interrupt is for the right device.
157a551c94aSIdo Barnea * If yes, disable it here and will be enable later.
158a551c94aSIdo Barnea */
159a551c94aSIdo Barneastatic irqreturn_t
160a551c94aSIdo Barneaigbuio_pci_irqhandler(int irq, struct uio_info *info)
161a551c94aSIdo Barnea{
162a551c94aSIdo Barnea	struct rte_uio_pci_dev *udev = info->priv;
163a551c94aSIdo Barnea
164a551c94aSIdo Barnea	/* Legacy mode need to mask in hardware */
165a551c94aSIdo Barnea	if (udev->mode == RTE_INTR_MODE_LEGACY &&
166a551c94aSIdo Barnea	    !pci_check_and_mask_intx(udev->pdev))
167a551c94aSIdo Barnea		return IRQ_NONE;
168a551c94aSIdo Barnea
169a551c94aSIdo Barnea	/* Message signal mode, no share IRQ and automasked */
170a551c94aSIdo Barnea	return IRQ_HANDLED;
171a551c94aSIdo Barnea}
172a551c94aSIdo Barnea
173a551c94aSIdo Barnea#ifdef CONFIG_XEN_DOM0
174a551c94aSIdo Barneastatic int
175a551c94aSIdo Barneaigbuio_dom0_mmap_phys(struct uio_info *info, struct vm_area_struct *vma)
176a551c94aSIdo Barnea{
177a551c94aSIdo Barnea	int idx;
178a551c94aSIdo Barnea
179a551c94aSIdo Barnea	idx = (int)vma->vm_pgoff;
180a551c94aSIdo Barnea	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
181a551c94aSIdo Barnea#ifdef HAVE_PTE_MASK_PAGE_IOMAP
182a551c94aSIdo Barnea	vma->vm_page_prot.pgprot |= _PAGE_IOMAP;
183a551c94aSIdo Barnea#endif
184a551c94aSIdo Barnea
185a551c94aSIdo Barnea	return remap_pfn_range(vma,
186a551c94aSIdo Barnea			vma->vm_start,
187a551c94aSIdo Barnea			info->mem[idx].addr >> PAGE_SHIFT,
188a551c94aSIdo Barnea			vma->vm_end - vma->vm_start,
189a551c94aSIdo Barnea			vma->vm_page_prot);
190a551c94aSIdo Barnea}
191a551c94aSIdo Barnea
192a551c94aSIdo Barnea/**
193a551c94aSIdo Barnea * This is uio device mmap method which will use igbuio mmap for Xen
194a551c94aSIdo Barnea * Dom0 environment.
195a551c94aSIdo Barnea */
196a551c94aSIdo Barneastatic int
197a551c94aSIdo Barneaigbuio_dom0_pci_mmap(struct uio_info *info, struct vm_area_struct *vma)
198a551c94aSIdo Barnea{
199a551c94aSIdo Barnea	int idx;
200a551c94aSIdo Barnea
201a551c94aSIdo Barnea	if (vma->vm_pgoff >= MAX_UIO_MAPS)
202a551c94aSIdo Barnea		return -EINVAL;
203a551c94aSIdo Barnea
204a551c94aSIdo Barnea	if (info->mem[vma->vm_pgoff].size == 0)
205a551c94aSIdo Barnea		return -EINVAL;
206a551c94aSIdo Barnea
207a551c94aSIdo Barnea	idx = (int)vma->vm_pgoff;
208a551c94aSIdo Barnea	switch (info->mem[idx].memtype) {
209a551c94aSIdo Barnea	case UIO_MEM_PHYS:
210a551c94aSIdo Barnea		return igbuio_dom0_mmap_phys(info, vma);
211a551c94aSIdo Barnea	case UIO_MEM_LOGICAL:
212a551c94aSIdo Barnea	case UIO_MEM_VIRTUAL:
213a551c94aSIdo Barnea	default:
214a551c94aSIdo Barnea		return -EINVAL;
215a551c94aSIdo Barnea	}
216a551c94aSIdo Barnea}
217a551c94aSIdo Barnea#endif
218a551c94aSIdo Barnea
219a551c94aSIdo Barnea/* Remap pci resources described by bar #pci_bar in uio resource n. */
220a551c94aSIdo Barneastatic int
221a551c94aSIdo Barneaigbuio_pci_setup_iomem(struct pci_dev *dev, struct uio_info *info,
222a551c94aSIdo Barnea		       int n, int pci_bar, const char *name)
223a551c94aSIdo Barnea{
224a551c94aSIdo Barnea	unsigned long addr, len;
225a551c94aSIdo Barnea	void *internal_addr;
226a551c94aSIdo Barnea
227a551c94aSIdo Barnea	if (n >= ARRAY_SIZE(info->mem))
228a551c94aSIdo Barnea		return -EINVAL;
229a551c94aSIdo Barnea
230a551c94aSIdo Barnea	addr = pci_resource_start(dev, pci_bar);
231a551c94aSIdo Barnea	len = pci_resource_len(dev, pci_bar);
232a551c94aSIdo Barnea	if (addr == 0 || len == 0)
233a551c94aSIdo Barnea		return -1;
234a551c94aSIdo Barnea	internal_addr = ioremap(addr, len);
235a551c94aSIdo Barnea	if (internal_addr == NULL)
236a551c94aSIdo Barnea		return -1;
237a551c94aSIdo Barnea	info->mem[n].name = name;
238a551c94aSIdo Barnea	info->mem[n].addr = addr;
239a551c94aSIdo Barnea	info->mem[n].internal_addr = internal_addr;
240a551c94aSIdo Barnea	info->mem[n].size = len;
241a551c94aSIdo Barnea	info->mem[n].memtype = UIO_MEM_PHYS;
242a551c94aSIdo Barnea	return 0;
243a551c94aSIdo Barnea}
244a551c94aSIdo Barnea
245a551c94aSIdo Barnea/* Get pci port io resources described by bar #pci_bar in uio resource n. */
246a551c94aSIdo Barneastatic int
247a551c94aSIdo Barneaigbuio_pci_setup_ioport(struct pci_dev *dev, struct uio_info *info,
248a551c94aSIdo Barnea		int n, int pci_bar, const char *name)
249a551c94aSIdo Barnea{
250a551c94aSIdo Barnea	unsigned long addr, len;
251a551c94aSIdo Barnea
252a551c94aSIdo Barnea	if (n >= ARRAY_SIZE(info->port))
253a551c94aSIdo Barnea		return -EINVAL;
254a551c94aSIdo Barnea
255a551c94aSIdo Barnea	addr = pci_resource_start(dev, pci_bar);
256a551c94aSIdo Barnea	len = pci_resource_len(dev, pci_bar);
257a551c94aSIdo Barnea	if (addr == 0 || len == 0)
258a551c94aSIdo Barnea		return -EINVAL;
259a551c94aSIdo Barnea
260a551c94aSIdo Barnea	info->port[n].name = name;
261a551c94aSIdo Barnea	info->port[n].start = addr;
262a551c94aSIdo Barnea	info->port[n].size = len;
263a551c94aSIdo Barnea	info->port[n].porttype = UIO_PORT_X86;
264a551c94aSIdo Barnea
265a551c94aSIdo Barnea	return 0;
266a551c94aSIdo Barnea}
267a551c94aSIdo Barnea
268a551c94aSIdo Barnea/* Unmap previously ioremap'd resources */
269a551c94aSIdo Barneastatic void
270a551c94aSIdo Barneaigbuio_pci_release_iomem(struct uio_info *info)
271a551c94aSIdo Barnea{
272a551c94aSIdo Barnea	int i;
273a551c94aSIdo Barnea
274a551c94aSIdo Barnea	for (i = 0; i < MAX_UIO_MAPS; i++) {
275a551c94aSIdo Barnea		if (info->mem[i].internal_addr)
276a551c94aSIdo Barnea			iounmap(info->mem[i].internal_addr);
277a551c94aSIdo Barnea	}
278a551c94aSIdo Barnea}
279a551c94aSIdo Barnea
280a551c94aSIdo Barneastatic int
281a551c94aSIdo Barneaigbuio_setup_bars(struct pci_dev *dev, struct uio_info *info)
282a551c94aSIdo Barnea{
283a551c94aSIdo Barnea	int i, iom, iop, ret;
284a551c94aSIdo Barnea	unsigned long flags;
285a551c94aSIdo Barnea	static const char *bar_names[PCI_STD_RESOURCE_END + 1]  = {
286a551c94aSIdo Barnea		"BAR0",
287a551c94aSIdo Barnea		"BAR1",
288a551c94aSIdo Barnea		"BAR2",
289a551c94aSIdo Barnea		"BAR3",
290a551c94aSIdo Barnea		"BAR4",
291a551c94aSIdo Barnea		"BAR5",
292a551c94aSIdo Barnea	};
293a551c94aSIdo Barnea
294a551c94aSIdo Barnea	iom = 0;
295a551c94aSIdo Barnea	iop = 0;
296a551c94aSIdo Barnea
297a551c94aSIdo Barnea	for (i = 0; i < ARRAY_SIZE(bar_names); i++) {
298a551c94aSIdo Barnea		if (pci_resource_len(dev, i) != 0 &&
299a551c94aSIdo Barnea				pci_resource_start(dev, i) != 0) {
300a551c94aSIdo Barnea			flags = pci_resource_flags(dev, i);
301a551c94aSIdo Barnea			if (flags & IORESOURCE_MEM) {
302a551c94aSIdo Barnea				ret = igbuio_pci_setup_iomem(dev, info, iom,
303a551c94aSIdo Barnea							     i, bar_names[i]);
304a551c94aSIdo Barnea				if (ret != 0)
305a551c94aSIdo Barnea					return ret;
306a551c94aSIdo Barnea				iom++;
307a551c94aSIdo Barnea			} else if (flags & IORESOURCE_IO) {
308a551c94aSIdo Barnea				ret = igbuio_pci_setup_ioport(dev, info, iop,
309a551c94aSIdo Barnea							      i, bar_names[i]);
310a551c94aSIdo Barnea				if (ret != 0)
311a551c94aSIdo Barnea					return ret;
312a551c94aSIdo Barnea				iop++;
313a551c94aSIdo Barnea			}
314a551c94aSIdo Barnea		}
315a551c94aSIdo Barnea	}
316a551c94aSIdo Barnea
317a551c94aSIdo Barnea	return (iom != 0) ? ret : -ENOENT;
318a551c94aSIdo Barnea}
319a551c94aSIdo Barnea
320a551c94aSIdo Barnea#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
321a551c94aSIdo Barneastatic int __devinit
322a551c94aSIdo Barnea#else
323a551c94aSIdo Barneastatic int
324a551c94aSIdo Barnea#endif
325a551c94aSIdo Barneaigbuio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
326a551c94aSIdo Barnea{
327a551c94aSIdo Barnea	struct rte_uio_pci_dev *udev;
328a551c94aSIdo Barnea	struct msix_entry msix_entry;
329a551c94aSIdo Barnea	int err;
330a551c94aSIdo Barnea
331a551c94aSIdo Barnea	udev = kzalloc(sizeof(struct rte_uio_pci_dev), GFP_KERNEL);
332a551c94aSIdo Barnea	if (!udev)
333a551c94aSIdo Barnea		return -ENOMEM;
334a551c94aSIdo Barnea
335a551c94aSIdo Barnea	/*
336a551c94aSIdo Barnea	 * enable device: ask low-level code to enable I/O and
337a551c94aSIdo Barnea	 * memory
338a551c94aSIdo Barnea	 */
339a551c94aSIdo Barnea	err = pci_enable_device(dev);
340a551c94aSIdo Barnea	if (err != 0) {
341a551c94aSIdo Barnea		dev_err(&dev->dev, "Cannot enable PCI device\n");
342a551c94aSIdo Barnea		goto fail_free;
343a551c94aSIdo Barnea	}
344a551c94aSIdo Barnea
345a551c94aSIdo Barnea	/* enable bus mastering on the device */
346a551c94aSIdo Barnea	pci_set_master(dev);
347a551c94aSIdo Barnea
348a551c94aSIdo Barnea	/* remap IO memory */
349a551c94aSIdo Barnea	err = igbuio_setup_bars(dev, &udev->info);
350a551c94aSIdo Barnea	if (err != 0)
351a551c94aSIdo Barnea		goto fail_release_iomem;
352a551c94aSIdo Barnea
353a551c94aSIdo Barnea	/* set 64-bit DMA mask */
354a551c94aSIdo Barnea	err = pci_set_dma_mask(dev,  DMA_BIT_MASK(64));
355a551c94aSIdo Barnea	if (err != 0) {
356a551c94aSIdo Barnea		dev_err(&dev->dev, "Cannot set DMA mask\n");
357a551c94aSIdo Barnea		goto fail_release_iomem;
358a551c94aSIdo Barnea	}
359a551c94aSIdo Barnea
360a551c94aSIdo Barnea	err = pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(64));
361a551c94aSIdo Barnea	if (err != 0) {
362a551c94aSIdo Barnea		dev_err(&dev->dev, "Cannot set consistent DMA mask\n");
363a551c94aSIdo Barnea		goto fail_release_iomem;
364a551c94aSIdo Barnea	}
365a551c94aSIdo Barnea
366a551c94aSIdo Barnea	/* fill uio infos */
367a551c94aSIdo Barnea	udev->info.name = "igb_uio";
368a551c94aSIdo Barnea	udev->info.version = "0.1";
369a551c94aSIdo Barnea	udev->info.handler = igbuio_pci_irqhandler;
370a551c94aSIdo Barnea	udev->info.irqcontrol = igbuio_pci_irqcontrol;
371a551c94aSIdo Barnea#ifdef CONFIG_XEN_DOM0
372a551c94aSIdo Barnea	/* check if the driver run on Xen Dom0 */
373a551c94aSIdo Barnea	if (xen_initial_domain())
374a551c94aSIdo Barnea		udev->info.mmap = igbuio_dom0_pci_mmap;
375a551c94aSIdo Barnea#endif
376a551c94aSIdo Barnea	udev->info.priv = udev;
377a551c94aSIdo Barnea	udev->pdev = dev;
378a551c94aSIdo Barnea
379a551c94aSIdo Barnea	switch (igbuio_intr_mode_preferred) {
380a551c94aSIdo Barnea	case RTE_INTR_MODE_MSIX:
381a551c94aSIdo Barnea		/* Only 1 msi-x vector needed */
382a551c94aSIdo Barnea		msix_entry.entry = 0;
383a551c94aSIdo Barnea		if (pci_enable_msix(dev, &msix_entry, 1) == 0) {
384a551c94aSIdo Barnea			dev_dbg(&dev->dev, "using MSI-X");
385a551c94aSIdo Barnea			udev->info.irq = msix_entry.vector;
386a551c94aSIdo Barnea			udev->mode = RTE_INTR_MODE_MSIX;
387a551c94aSIdo Barnea			break;
388a551c94aSIdo Barnea		}
389a551c94aSIdo Barnea		/* fall back to INTX */
390a551c94aSIdo Barnea	case RTE_INTR_MODE_LEGACY:
391a551c94aSIdo Barnea		if (pci_intx_mask_supported(dev)) {
392a551c94aSIdo Barnea			dev_dbg(&dev->dev, "using INTX");
393a551c94aSIdo Barnea			udev->info.irq_flags = IRQF_SHARED;
394a551c94aSIdo Barnea			udev->info.irq = dev->irq;
395a551c94aSIdo Barnea			udev->mode = RTE_INTR_MODE_LEGACY;
396a551c94aSIdo Barnea			break;
397a551c94aSIdo Barnea		}
398a551c94aSIdo Barnea		dev_notice(&dev->dev, "PCI INTX mask not supported\n");
399a551c94aSIdo Barnea		/* fall back to no IRQ */
400a551c94aSIdo Barnea	case RTE_INTR_MODE_NONE:
401a551c94aSIdo Barnea		udev->mode = RTE_INTR_MODE_NONE;
402a551c94aSIdo Barnea		udev->info.irq = 0;
403a551c94aSIdo Barnea		break;
404a551c94aSIdo Barnea
405a551c94aSIdo Barnea	default:
406a551c94aSIdo Barnea		dev_err(&dev->dev, "invalid IRQ mode %u",
407a551c94aSIdo Barnea			igbuio_intr_mode_preferred);
408a551c94aSIdo Barnea		err = -EINVAL;
409a551c94aSIdo Barnea		goto fail_release_iomem;
410a551c94aSIdo Barnea	}
411a551c94aSIdo Barnea
412a551c94aSIdo Barnea	err = sysfs_create_group(&dev->dev.kobj, &dev_attr_grp);
413a551c94aSIdo Barnea	if (err != 0)
414a551c94aSIdo Barnea		goto fail_release_iomem;
415a551c94aSIdo Barnea
416a551c94aSIdo Barnea	/* register uio driver */
417a551c94aSIdo Barnea	err = uio_register_device(&dev->dev, &udev->info);
418a551c94aSIdo Barnea	if (err != 0)
419a551c94aSIdo Barnea		goto fail_remove_group;
420a551c94aSIdo Barnea
421a551c94aSIdo Barnea	pci_set_drvdata(dev, udev);
422a551c94aSIdo Barnea
423a551c94aSIdo Barnea	dev_info(&dev->dev, "uio device registered with irq %lx\n",
424a551c94aSIdo Barnea		 udev->info.irq);
425a551c94aSIdo Barnea
426a551c94aSIdo Barnea	return 0;
427a551c94aSIdo Barnea
428a551c94aSIdo Barneafail_remove_group:
429a551c94aSIdo Barnea	sysfs_remove_group(&dev->dev.kobj, &dev_attr_grp);
430a551c94aSIdo Barneafail_release_iomem:
431a551c94aSIdo Barnea	igbuio_pci_release_iomem(&udev->info);
432a551c94aSIdo Barnea	if (udev->mode == RTE_INTR_MODE_MSIX)
433a551c94aSIdo Barnea		pci_disable_msix(udev->pdev);
434a551c94aSIdo Barnea	pci_disable_device(dev);
435a551c94aSIdo Barneafail_free:
436a551c94aSIdo Barnea	kfree(udev);
437a551c94aSIdo Barnea
438a551c94aSIdo Barnea	return err;
439a551c94aSIdo Barnea}
440a551c94aSIdo Barnea
441a551c94aSIdo Barneastatic void
442a551c94aSIdo Barneaigbuio_pci_remove(struct pci_dev *dev)
443a551c94aSIdo Barnea{
444a551c94aSIdo Barnea	struct rte_uio_pci_dev *udev = pci_get_drvdata(dev);
445a551c94aSIdo Barnea
446a551c94aSIdo Barnea	sysfs_remove_group(&dev->dev.kobj, &dev_attr_grp);
447a551c94aSIdo Barnea	uio_unregister_device(&udev->info);
448a551c94aSIdo Barnea	igbuio_pci_release_iomem(&udev->info);
449a551c94aSIdo Barnea	if (udev->mode == RTE_INTR_MODE_MSIX)
450a551c94aSIdo Barnea		pci_disable_msix(dev);
451a551c94aSIdo Barnea	pci_disable_device(dev);
452a551c94aSIdo Barnea	pci_set_drvdata(dev, NULL);
453a551c94aSIdo Barnea	kfree(udev);
454a551c94aSIdo Barnea}
455a551c94aSIdo Barnea
456a551c94aSIdo Barneastatic int
457a551c94aSIdo Barneaigbuio_config_intr_mode(char *intr_str)
458a551c94aSIdo Barnea{
459a551c94aSIdo Barnea	if (!intr_str) {
460a551c94aSIdo Barnea		pr_info("Use MSIX interrupt by default\n");
461a551c94aSIdo Barnea		return 0;
462a551c94aSIdo Barnea	}
463a551c94aSIdo Barnea
464a551c94aSIdo Barnea	if (!strcmp(intr_str, RTE_INTR_MODE_MSIX_NAME)) {
465a551c94aSIdo Barnea		igbuio_intr_mode_preferred = RTE_INTR_MODE_MSIX;
466a551c94aSIdo Barnea		pr_info("Use MSIX interrupt\n");
467a551c94aSIdo Barnea	} else if (!strcmp(intr_str, RTE_INTR_MODE_LEGACY_NAME)) {
468a551c94aSIdo Barnea		igbuio_intr_mode_preferred = RTE_INTR_MODE_LEGACY;
469a551c94aSIdo Barnea		pr_info("Use legacy interrupt\n");
470a551c94aSIdo Barnea	} else {
471a551c94aSIdo Barnea		pr_info("Error: bad parameter - %s\n", intr_str);
472a551c94aSIdo Barnea		return -EINVAL;
473a551c94aSIdo Barnea	}
474a551c94aSIdo Barnea
475a551c94aSIdo Barnea	return 0;
476a551c94aSIdo Barnea}
477a551c94aSIdo Barnea
478a551c94aSIdo Barneastatic struct pci_driver igbuio_pci_driver = {
479a551c94aSIdo Barnea	.name = "igb_uio",
480a551c94aSIdo Barnea	.id_table = NULL,
481a551c94aSIdo Barnea	.probe = igbuio_pci_probe,
482a551c94aSIdo Barnea	.remove = igbuio_pci_remove,
483a551c94aSIdo Barnea};
484a551c94aSIdo Barnea
485a551c94aSIdo Barneastatic int __init
486a551c94aSIdo Barneaigbuio_pci_init_module(void)
487a551c94aSIdo Barnea{
488a551c94aSIdo Barnea	int ret;
489a551c94aSIdo Barnea
490a551c94aSIdo Barnea	ret = igbuio_config_intr_mode(intr_mode);
491a551c94aSIdo Barnea	if (ret < 0)
492a551c94aSIdo Barnea		return ret;
493a551c94aSIdo Barnea
494a551c94aSIdo Barnea	return pci_register_driver(&igbuio_pci_driver);
495a551c94aSIdo Barnea}
496a551c94aSIdo Barnea
497a551c94aSIdo Barneastatic void __exit
498a551c94aSIdo Barneaigbuio_pci_exit_module(void)
499a551c94aSIdo Barnea{
500a551c94aSIdo Barnea	pci_unregister_driver(&igbuio_pci_driver);
501a551c94aSIdo Barnea}
502a551c94aSIdo Barnea
503a551c94aSIdo Barneamodule_init(igbuio_pci_init_module);
504a551c94aSIdo Barneamodule_exit(igbuio_pci_exit_module);
505a551c94aSIdo Barnea
506a551c94aSIdo Barneamodule_param(intr_mode, charp, S_IRUGO);
507a551c94aSIdo BarneaMODULE_PARM_DESC(intr_mode,
508a551c94aSIdo Barnea"igb_uio interrupt mode (default=msix):\n"
509a551c94aSIdo Barnea"    " RTE_INTR_MODE_MSIX_NAME "       Use MSIX interrupt\n"
510a551c94aSIdo Barnea"    " RTE_INTR_MODE_LEGACY_NAME "     Use Legacy interrupt\n"
511a551c94aSIdo Barnea"\n");
512a551c94aSIdo Barnea
513a551c94aSIdo BarneaMODULE_DESCRIPTION("UIO driver for Intel IGB PCI cards");
514a551c94aSIdo BarneaMODULE_LICENSE("GPL");
515a551c94aSIdo BarneaMODULE_AUTHOR("Intel Corporation");