189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson/*
289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson * VFIO PCI interrupt handling
389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson *
489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson * Copyright (C) 2012 Red Hat, Inc.  All rights reserved.
589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson *     Author: Alex Williamson <alex.williamson@redhat.com>
689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson *
789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson * This program is free software; you can redistribute it and/or modify
889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson * it under the terms of the GNU General Public License version 2 as
989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson * published by the Free Software Foundation.
1089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson *
1189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson * Derived from original vfio:
1289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson * Copyright 2010 Cisco Systems, Inc.  All rights reserved.
1389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson * Author: Tom Lyon, pugs@cisco.com
1489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson */
1589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
1689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson#include <linux/device.h>
1789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson#include <linux/interrupt.h>
1889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson#include <linux/eventfd.h>
19b8f02af096b1fc9fd46680cbe55214e477eb76d3Gavin Shan#include <linux/msi.h>
2089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson#include <linux/pci.h>
2189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson#include <linux/file.h>
2289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson#include <linux/poll.h>
2389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson#include <linux/vfio.h>
2489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson#include <linux/wait.h>
2589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson#include <linux/workqueue.h>
2625e9789ddd9d14a8971f4a421d04f282719ab733Arnd Bergmann#include <linux/slab.h>
2789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
2889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson#include "vfio_pci_private.h"
2989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
3089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson/*
3189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson * IRQfd - generic
3289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson */
3389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstruct virqfd {
3489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct vfio_pci_device	*vdev;
3589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct eventfd_ctx	*eventfd;
3689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	int			(*handler)(struct vfio_pci_device *, void *);
3789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	void			(*thread)(struct vfio_pci_device *, void *);
3889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	void			*data;
3989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct work_struct	inject;
4089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	wait_queue_t		wait;
4189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	poll_table		pt;
4289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct work_struct	shutdown;
4389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct virqfd		**pvirqfd;
4489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson};
4589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
4689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic struct workqueue_struct *vfio_irqfd_cleanup_wq;
4789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
4889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonint __init vfio_pci_virqfd_init(void)
4989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
5089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	vfio_irqfd_cleanup_wq =
5189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		create_singlethread_workqueue("vfio-irqfd-cleanup");
5289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!vfio_irqfd_cleanup_wq)
5389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -ENOMEM;
5489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
5589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	return 0;
5689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
5789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
5889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonvoid vfio_pci_virqfd_exit(void)
5989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
6089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	destroy_workqueue(vfio_irqfd_cleanup_wq);
6189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
6289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
6389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic void virqfd_deactivate(struct virqfd *virqfd)
6489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
6589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	queue_work(vfio_irqfd_cleanup_wq, &virqfd->shutdown);
6689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
6789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
6889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic int virqfd_wakeup(wait_queue_t *wait, unsigned mode, int sync, void *key)
6989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
7089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct virqfd *virqfd = container_of(wait, struct virqfd, wait);
7189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	unsigned long flags = (unsigned long)key;
7289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
7389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (flags & POLLIN) {
7489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		/* An event has been signaled, call function */
7589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if ((!virqfd->handler ||
7689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		     virqfd->handler(virqfd->vdev, virqfd->data)) &&
7789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		    virqfd->thread)
7889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			schedule_work(&virqfd->inject);
7989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
8089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
81b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	if (flags & POLLHUP) {
82b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		unsigned long flags;
83b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		spin_lock_irqsave(&virqfd->vdev->irqlock, flags);
84b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson
85b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		/*
86b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		 * The eventfd is closing, if the virqfd has not yet been
87b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		 * queued for release, as determined by testing whether the
88b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		 * vdev pointer to it is still valid, queue it now.  As
89b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		 * with kvm irqfds, we know we won't race against the virqfd
90b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		 * going away because we hold wqh->lock to get here.
91b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		 */
92b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		if (*(virqfd->pvirqfd) == virqfd) {
93b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson			*(virqfd->pvirqfd) = NULL;
94b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson			virqfd_deactivate(virqfd);
95b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		}
96b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson
97b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		spin_unlock_irqrestore(&virqfd->vdev->irqlock, flags);
98b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	}
9989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
10089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	return 0;
10189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
10289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
10389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic void virqfd_ptable_queue_proc(struct file *file,
10489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson				     wait_queue_head_t *wqh, poll_table *pt)
10589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
10689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct virqfd *virqfd = container_of(pt, struct virqfd, pt);
10789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	add_wait_queue(wqh, &virqfd->wait);
10889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
10989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
11089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic void virqfd_shutdown(struct work_struct *work)
11189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
11289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct virqfd *virqfd = container_of(work, struct virqfd, shutdown);
11389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	u64 cnt;
11489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
11589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	eventfd_ctx_remove_wait_queue(virqfd->eventfd, &virqfd->wait, &cnt);
11689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	flush_work(&virqfd->inject);
11789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	eventfd_ctx_put(virqfd->eventfd);
11889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
11989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	kfree(virqfd);
12089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
12189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
12289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic void virqfd_inject(struct work_struct *work)
12389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
12489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct virqfd *virqfd = container_of(work, struct virqfd, inject);
12589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (virqfd->thread)
12689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		virqfd->thread(virqfd->vdev, virqfd->data);
12789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
12889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
12989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic int virqfd_enable(struct vfio_pci_device *vdev,
13089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			 int (*handler)(struct vfio_pci_device *, void *),
13189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			 void (*thread)(struct vfio_pci_device *, void *),
13289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			 void *data, struct virqfd **pvirqfd, int fd)
13389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
13420e77457842f4cd253d093f08f0cce1a73afb7dbAlex Williamson	struct fd irqfd;
13520e77457842f4cd253d093f08f0cce1a73afb7dbAlex Williamson	struct eventfd_ctx *ctx;
13689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct virqfd *virqfd;
13789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	int ret = 0;
13889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	unsigned int events;
13989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
14089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	virqfd = kzalloc(sizeof(*virqfd), GFP_KERNEL);
14189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!virqfd)
14289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -ENOMEM;
14389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
14489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	virqfd->pvirqfd = pvirqfd;
14589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	virqfd->vdev = vdev;
14689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	virqfd->handler = handler;
14789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	virqfd->thread = thread;
14889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	virqfd->data = data;
14989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
15089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	INIT_WORK(&virqfd->shutdown, virqfd_shutdown);
15189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	INIT_WORK(&virqfd->inject, virqfd_inject);
15289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
15320e77457842f4cd253d093f08f0cce1a73afb7dbAlex Williamson	irqfd = fdget(fd);
15420e77457842f4cd253d093f08f0cce1a73afb7dbAlex Williamson	if (!irqfd.file) {
15520e77457842f4cd253d093f08f0cce1a73afb7dbAlex Williamson		ret = -EBADF;
15620e77457842f4cd253d093f08f0cce1a73afb7dbAlex Williamson		goto err_fd;
15789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
15889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
15920e77457842f4cd253d093f08f0cce1a73afb7dbAlex Williamson	ctx = eventfd_ctx_fileget(irqfd.file);
16089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (IS_ERR(ctx)) {
16189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		ret = PTR_ERR(ctx);
16220e77457842f4cd253d093f08f0cce1a73afb7dbAlex Williamson		goto err_ctx;
16389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
16489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
16589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	virqfd->eventfd = ctx;
16689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
16789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	/*
168b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	 * virqfds can be released by closing the eventfd or directly
169b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	 * through ioctl.  These are both done through a workqueue, so
170b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	 * we update the pointer to the virqfd under lock to avoid
171b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	 * pushing multiple jobs to release the same virqfd.
172b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	 */
173b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	spin_lock_irq(&vdev->irqlock);
174b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson
175b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	if (*pvirqfd) {
176b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		spin_unlock_irq(&vdev->irqlock);
177b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		ret = -EBUSY;
17820e77457842f4cd253d093f08f0cce1a73afb7dbAlex Williamson		goto err_busy;
179b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	}
180b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	*pvirqfd = virqfd;
181b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson
182b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	spin_unlock_irq(&vdev->irqlock);
183b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson
184b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	/*
18589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 * Install our own custom wake-up handling so we are notified via
18689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 * a callback whenever someone signals the underlying eventfd.
18789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 */
18889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	init_waitqueue_func_entry(&virqfd->wait, virqfd_wakeup);
18989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	init_poll_funcptr(&virqfd->pt, virqfd_ptable_queue_proc);
19089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
19120e77457842f4cd253d093f08f0cce1a73afb7dbAlex Williamson	events = irqfd.file->f_op->poll(irqfd.file, &virqfd->pt);
19289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
19389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	/*
19489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 * Check if there was an event already pending on the eventfd
19589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 * before we registered and trigger it as if we didn't miss it.
19689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 */
19789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (events & POLLIN) {
19889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if ((!handler || handler(vdev, data)) && thread)
19989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			schedule_work(&virqfd->inject);
20089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
20189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
20289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	/*
20389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 * Do not drop the file until the irqfd is fully initialized,
20489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 * otherwise we might race against the POLLHUP.
20589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 */
20620e77457842f4cd253d093f08f0cce1a73afb7dbAlex Williamson	fdput(irqfd);
20789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
20889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	return 0;
20920e77457842f4cd253d093f08f0cce1a73afb7dbAlex Williamsonerr_busy:
21020e77457842f4cd253d093f08f0cce1a73afb7dbAlex Williamson	eventfd_ctx_put(ctx);
21120e77457842f4cd253d093f08f0cce1a73afb7dbAlex Williamsonerr_ctx:
21220e77457842f4cd253d093f08f0cce1a73afb7dbAlex Williamson	fdput(irqfd);
21320e77457842f4cd253d093f08f0cce1a73afb7dbAlex Williamsonerr_fd:
21489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	kfree(virqfd);
21589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
21689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	return ret;
21789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
21889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
219b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamsonstatic void virqfd_disable(struct vfio_pci_device *vdev,
220b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson			   struct virqfd **pvirqfd)
22189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
222b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	unsigned long flags;
223b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson
224b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	spin_lock_irqsave(&vdev->irqlock, flags);
225b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson
226b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	if (*pvirqfd) {
227b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		virqfd_deactivate(*pvirqfd);
228b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		*pvirqfd = NULL;
229b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	}
23089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
231b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	spin_unlock_irqrestore(&vdev->irqlock, flags);
23289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
233b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	/*
234b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	 * Block until we know all outstanding shutdown jobs have completed.
235b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	 * Even if we don't queue the job, flush the wq to be sure it's
236b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	 * been released.
237b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	 */
23889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	flush_workqueue(vfio_irqfd_cleanup_wq);
23989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
24089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
24189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson/*
24289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson * INTx
24389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson */
24489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic void vfio_send_intx_eventfd(struct vfio_pci_device *vdev, void *unused)
24589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
24689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (likely(is_intx(vdev) && !vdev->virq_disabled))
24789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		eventfd_signal(vdev->ctx[0].trigger, 1);
24889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
24989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
25089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonvoid vfio_pci_intx_mask(struct vfio_pci_device *vdev)
25189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
25289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct pci_dev *pdev = vdev->pdev;
25389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	unsigned long flags;
25489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
25589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	spin_lock_irqsave(&vdev->irqlock, flags);
25689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
25789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	/*
25889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 * Masking can come from interrupt, ioctl, or config space
25989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 * via INTx disable.  The latter means this can get called
26089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 * even when not using intx delivery.  In this case, just
26189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 * try to have the physical bit follow the virtual bit.
26289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 */
26389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (unlikely(!is_intx(vdev))) {
26489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if (vdev->pci_2_3)
26589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			pci_intx(pdev, 0);
26689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	} else if (!vdev->ctx[0].masked) {
26789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		/*
26889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		 * Can't use check_and_mask here because we always want to
26989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		 * mask, not just when something is pending.
27089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		 */
27189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if (vdev->pci_2_3)
27289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			pci_intx(pdev, 0);
27389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		else
27489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			disable_irq_nosync(pdev->irq);
27589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
27689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		vdev->ctx[0].masked = true;
27789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
27889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
27989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	spin_unlock_irqrestore(&vdev->irqlock, flags);
28089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
28189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
28289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson/*
28389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson * If this is triggered by an eventfd, we can't call eventfd_signal
28489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson * or else we'll deadlock on the eventfd wait queue.  Return >0 when
28589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson * a signal is necessary, which can then be handled via a work queue
28689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson * or directly depending on the caller.
28789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson */
2880bced2f7280cd12b66229ba55d05c62a4eef6cfdWei Yongjunstatic int vfio_pci_intx_unmask_handler(struct vfio_pci_device *vdev,
2890bced2f7280cd12b66229ba55d05c62a4eef6cfdWei Yongjun					void *unused)
29089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
29189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct pci_dev *pdev = vdev->pdev;
29289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	unsigned long flags;
29389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	int ret = 0;
29489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
29589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	spin_lock_irqsave(&vdev->irqlock, flags);
29689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
29789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	/*
29889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 * Unmasking comes from ioctl or config, so again, have the
29989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 * physical bit follow the virtual even when not using INTx.
30089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 */
30189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (unlikely(!is_intx(vdev))) {
30289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if (vdev->pci_2_3)
30389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			pci_intx(pdev, 1);
30489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	} else if (vdev->ctx[0].masked && !vdev->virq_disabled) {
30589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		/*
30689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		 * A pending interrupt here would immediately trigger,
30789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		 * but we can avoid that overhead by just re-sending
30889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		 * the interrupt to the user.
30989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		 */
31089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if (vdev->pci_2_3) {
31189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			if (!pci_check_and_unmask_intx(pdev))
31289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson				ret = 1;
31389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		} else
31489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			enable_irq(pdev->irq);
31589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
31689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		vdev->ctx[0].masked = (ret > 0);
31789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
31889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
31989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	spin_unlock_irqrestore(&vdev->irqlock, flags);
32089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
32189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	return ret;
32289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
32389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
32489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonvoid vfio_pci_intx_unmask(struct vfio_pci_device *vdev)
32589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
32689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (vfio_pci_intx_unmask_handler(vdev, NULL) > 0)
32789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		vfio_send_intx_eventfd(vdev, NULL);
32889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
32989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
33089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic irqreturn_t vfio_intx_handler(int irq, void *dev_id)
33189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
33289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct vfio_pci_device *vdev = dev_id;
33389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	unsigned long flags;
33489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	int ret = IRQ_NONE;
33589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
33689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	spin_lock_irqsave(&vdev->irqlock, flags);
33789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
33889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!vdev->pci_2_3) {
33989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		disable_irq_nosync(vdev->pdev->irq);
34089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		vdev->ctx[0].masked = true;
34189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		ret = IRQ_HANDLED;
34289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	} else if (!vdev->ctx[0].masked &&  /* may be shared */
34389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		   pci_check_and_mask_intx(vdev->pdev)) {
34489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		vdev->ctx[0].masked = true;
34589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		ret = IRQ_HANDLED;
34689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
34789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
34889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	spin_unlock_irqrestore(&vdev->irqlock, flags);
34989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
35089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (ret == IRQ_HANDLED)
35189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		vfio_send_intx_eventfd(vdev, NULL);
35289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
35389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	return ret;
35489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
35589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
35689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic int vfio_intx_enable(struct vfio_pci_device *vdev)
35789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
35889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!is_irq_none(vdev))
35989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -EINVAL;
36089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
36189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!vdev->pdev->irq)
36289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -ENODEV;
36389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
36489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	vdev->ctx = kzalloc(sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL);
36589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!vdev->ctx)
36689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -ENOMEM;
36789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
36889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	vdev->num_ctx = 1;
369899649b7d4ead76c19e39251ca886eebe3f811a8Alex Williamson
370899649b7d4ead76c19e39251ca886eebe3f811a8Alex Williamson	/*
371899649b7d4ead76c19e39251ca886eebe3f811a8Alex Williamson	 * If the virtual interrupt is masked, restore it.  Devices
372899649b7d4ead76c19e39251ca886eebe3f811a8Alex Williamson	 * supporting DisINTx can be masked at the hardware level
373899649b7d4ead76c19e39251ca886eebe3f811a8Alex Williamson	 * here, non-PCI-2.3 devices will have to wait until the
374899649b7d4ead76c19e39251ca886eebe3f811a8Alex Williamson	 * interrupt is enabled.
375899649b7d4ead76c19e39251ca886eebe3f811a8Alex Williamson	 */
376899649b7d4ead76c19e39251ca886eebe3f811a8Alex Williamson	vdev->ctx[0].masked = vdev->virq_disabled;
377899649b7d4ead76c19e39251ca886eebe3f811a8Alex Williamson	if (vdev->pci_2_3)
378899649b7d4ead76c19e39251ca886eebe3f811a8Alex Williamson		pci_intx(vdev->pdev, !vdev->ctx[0].masked);
379899649b7d4ead76c19e39251ca886eebe3f811a8Alex Williamson
38089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	vdev->irq_type = VFIO_PCI_INTX_IRQ_INDEX;
38189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
38289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	return 0;
38389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
38489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
38589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic int vfio_intx_set_signal(struct vfio_pci_device *vdev, int fd)
38689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
38789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct pci_dev *pdev = vdev->pdev;
38889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	unsigned long irqflags = IRQF_SHARED;
38989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct eventfd_ctx *trigger;
39089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	unsigned long flags;
39189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	int ret;
39289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
39389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (vdev->ctx[0].trigger) {
39489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		free_irq(pdev->irq, vdev);
39589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		kfree(vdev->ctx[0].name);
39689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		eventfd_ctx_put(vdev->ctx[0].trigger);
39789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		vdev->ctx[0].trigger = NULL;
39889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
39989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
40089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (fd < 0) /* Disable only */
40189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return 0;
40289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
40389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	vdev->ctx[0].name = kasprintf(GFP_KERNEL, "vfio-intx(%s)",
40489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson				      pci_name(pdev));
40589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!vdev->ctx[0].name)
40689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -ENOMEM;
40789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
40889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	trigger = eventfd_ctx_fdget(fd);
40989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (IS_ERR(trigger)) {
41089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		kfree(vdev->ctx[0].name);
41189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return PTR_ERR(trigger);
41289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
41389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
4149dbdfd23b7638d054f3b0e70c64dfb9f297f2a9fAlex Williamson	vdev->ctx[0].trigger = trigger;
4159dbdfd23b7638d054f3b0e70c64dfb9f297f2a9fAlex Williamson
41689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!vdev->pci_2_3)
41789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		irqflags = 0;
41889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
41989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	ret = request_irq(pdev->irq, vfio_intx_handler,
42089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			  irqflags, vdev->ctx[0].name, vdev);
42189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (ret) {
4229dbdfd23b7638d054f3b0e70c64dfb9f297f2a9fAlex Williamson		vdev->ctx[0].trigger = NULL;
42389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		kfree(vdev->ctx[0].name);
42489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		eventfd_ctx_put(trigger);
42589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return ret;
42689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
42789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
42889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	/*
42989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 * INTx disable will stick across the new irq setup,
43089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 * disable_irq won't.
43189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	 */
43289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	spin_lock_irqsave(&vdev->irqlock, flags);
433899649b7d4ead76c19e39251ca886eebe3f811a8Alex Williamson	if (!vdev->pci_2_3 && vdev->ctx[0].masked)
43489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		disable_irq_nosync(pdev->irq);
43589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	spin_unlock_irqrestore(&vdev->irqlock, flags);
43689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
43789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	return 0;
43889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
43989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
44089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic void vfio_intx_disable(struct vfio_pci_device *vdev)
44189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
44289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	vfio_intx_set_signal(vdev, -1);
443b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	virqfd_disable(vdev, &vdev->ctx[0].unmask);
444b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson	virqfd_disable(vdev, &vdev->ctx[0].mask);
44589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	vdev->irq_type = VFIO_PCI_NUM_IRQS;
44689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	vdev->num_ctx = 0;
44789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	kfree(vdev->ctx);
44889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
44989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
45089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson/*
45189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson * MSI/MSI-X
45289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson */
45389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic irqreturn_t vfio_msihandler(int irq, void *arg)
45489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
45589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct eventfd_ctx *trigger = arg;
45689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
45789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	eventfd_signal(trigger, 1);
45889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	return IRQ_HANDLED;
45989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
46089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
46189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic int vfio_msi_enable(struct vfio_pci_device *vdev, int nvec, bool msix)
46289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
46389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct pci_dev *pdev = vdev->pdev;
46489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	int ret;
46589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
46689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!is_irq_none(vdev))
46789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -EINVAL;
46889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
46989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	vdev->ctx = kzalloc(nvec * sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL);
47089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!vdev->ctx)
47189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -ENOMEM;
47289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
47389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (msix) {
47489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		int i;
47589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
47689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		vdev->msix = kzalloc(nvec * sizeof(struct msix_entry),
47789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson				     GFP_KERNEL);
47889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if (!vdev->msix) {
47989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			kfree(vdev->ctx);
48089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			return -ENOMEM;
48189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		}
48289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
48389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		for (i = 0; i < nvec; i++)
48489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			vdev->msix[i].entry = i;
48589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
48694cccde648d32abe61e2d0d1b18178f3027f1a78Alexander Gordeev		ret = pci_enable_msix_range(pdev, vdev->msix, 1, nvec);
48794cccde648d32abe61e2d0d1b18178f3027f1a78Alexander Gordeev		if (ret < nvec) {
48894cccde648d32abe61e2d0d1b18178f3027f1a78Alexander Gordeev			if (ret > 0)
48994cccde648d32abe61e2d0d1b18178f3027f1a78Alexander Gordeev				pci_disable_msix(pdev);
49089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			kfree(vdev->msix);
49189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			kfree(vdev->ctx);
49289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			return ret;
49389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		}
49489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	} else {
49594cccde648d32abe61e2d0d1b18178f3027f1a78Alexander Gordeev		ret = pci_enable_msi_range(pdev, 1, nvec);
49694cccde648d32abe61e2d0d1b18178f3027f1a78Alexander Gordeev		if (ret < nvec) {
49794cccde648d32abe61e2d0d1b18178f3027f1a78Alexander Gordeev			if (ret > 0)
49894cccde648d32abe61e2d0d1b18178f3027f1a78Alexander Gordeev				pci_disable_msi(pdev);
49989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			kfree(vdev->ctx);
50089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			return ret;
50189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		}
50289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
50389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
50489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	vdev->num_ctx = nvec;
50589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	vdev->irq_type = msix ? VFIO_PCI_MSIX_IRQ_INDEX :
50689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson				VFIO_PCI_MSI_IRQ_INDEX;
50789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
50889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!msix) {
50989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		/*
51089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		 * Compute the virtual hardware field for max msi vectors -
51189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		 * it is the log base 2 of the number of vectors.
51289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		 */
51389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		vdev->msi_qmax = fls(nvec * 2 - 1) - 1;
51489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
51589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
51689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	return 0;
51789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
51889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
51989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic int vfio_msi_set_vector_signal(struct vfio_pci_device *vdev,
52089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson				      int vector, int fd, bool msix)
52189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
52289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct pci_dev *pdev = vdev->pdev;
52389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	int irq = msix ? vdev->msix[vector].vector : pdev->irq + vector;
52489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	char *name = msix ? "vfio-msix" : "vfio-msi";
52589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct eventfd_ctx *trigger;
52689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	int ret;
52789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
52889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (vector >= vdev->num_ctx)
52989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -EINVAL;
53089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
53189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (vdev->ctx[vector].trigger) {
53289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		free_irq(irq, vdev->ctx[vector].trigger);
53389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		kfree(vdev->ctx[vector].name);
53489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		eventfd_ctx_put(vdev->ctx[vector].trigger);
53589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		vdev->ctx[vector].trigger = NULL;
53689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
53789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
53889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (fd < 0)
53989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return 0;
54089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
54189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	vdev->ctx[vector].name = kasprintf(GFP_KERNEL, "%s[%d](%s)",
54289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson					   name, vector, pci_name(pdev));
54389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!vdev->ctx[vector].name)
54489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -ENOMEM;
54589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
54689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	trigger = eventfd_ctx_fdget(fd);
54789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (IS_ERR(trigger)) {
54889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		kfree(vdev->ctx[vector].name);
54989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return PTR_ERR(trigger);
55089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
55189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
552b8f02af096b1fc9fd46680cbe55214e477eb76d3Gavin Shan	/*
553b8f02af096b1fc9fd46680cbe55214e477eb76d3Gavin Shan	 * The MSIx vector table resides in device memory which may be cleared
554b8f02af096b1fc9fd46680cbe55214e477eb76d3Gavin Shan	 * via backdoor resets. We don't allow direct access to the vector
555b8f02af096b1fc9fd46680cbe55214e477eb76d3Gavin Shan	 * table so even if a userspace driver attempts to save/restore around
556b8f02af096b1fc9fd46680cbe55214e477eb76d3Gavin Shan	 * such a reset it would be unsuccessful. To avoid this, restore the
557b8f02af096b1fc9fd46680cbe55214e477eb76d3Gavin Shan	 * cached value of the message prior to enabling.
558b8f02af096b1fc9fd46680cbe55214e477eb76d3Gavin Shan	 */
559b8f02af096b1fc9fd46680cbe55214e477eb76d3Gavin Shan	if (msix) {
560b8f02af096b1fc9fd46680cbe55214e477eb76d3Gavin Shan		struct msi_msg msg;
561b8f02af096b1fc9fd46680cbe55214e477eb76d3Gavin Shan
562b8f02af096b1fc9fd46680cbe55214e477eb76d3Gavin Shan		get_cached_msi_msg(irq, &msg);
563b8f02af096b1fc9fd46680cbe55214e477eb76d3Gavin Shan		write_msi_msg(irq, &msg);
564b8f02af096b1fc9fd46680cbe55214e477eb76d3Gavin Shan	}
565b8f02af096b1fc9fd46680cbe55214e477eb76d3Gavin Shan
56689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	ret = request_irq(irq, vfio_msihandler, 0,
56789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			  vdev->ctx[vector].name, trigger);
56889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (ret) {
56989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		kfree(vdev->ctx[vector].name);
57089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		eventfd_ctx_put(trigger);
57189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return ret;
57289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
57389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
57489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	vdev->ctx[vector].trigger = trigger;
57589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
57689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	return 0;
57789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
57889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
57989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic int vfio_msi_set_block(struct vfio_pci_device *vdev, unsigned start,
58089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			      unsigned count, int32_t *fds, bool msix)
58189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
58289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	int i, j, ret = 0;
58389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
58489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (start + count > vdev->num_ctx)
58589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -EINVAL;
58689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
58789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	for (i = 0, j = start; i < count && !ret; i++, j++) {
58889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		int fd = fds ? fds[i] : -1;
58989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		ret = vfio_msi_set_vector_signal(vdev, j, fd, msix);
59089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
59189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
59289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (ret) {
59389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		for (--j; j >= start; j--)
59489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			vfio_msi_set_vector_signal(vdev, j, -1, msix);
59589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
59689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
59789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	return ret;
59889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
59989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
60089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic void vfio_msi_disable(struct vfio_pci_device *vdev, bool msix)
60189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
60289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	struct pci_dev *pdev = vdev->pdev;
60389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	int i;
60489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
60589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	vfio_msi_set_block(vdev, 0, vdev->num_ctx, NULL, msix);
60689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
60789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	for (i = 0; i < vdev->num_ctx; i++) {
608b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		virqfd_disable(vdev, &vdev->ctx[i].unmask);
609b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		virqfd_disable(vdev, &vdev->ctx[i].mask);
61089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
61189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
61289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (msix) {
61389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		pci_disable_msix(vdev->pdev);
61489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		kfree(vdev->msix);
61589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	} else
61689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		pci_disable_msi(pdev);
61789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
61889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	vdev->irq_type = VFIO_PCI_NUM_IRQS;
61989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	vdev->num_ctx = 0;
62089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	kfree(vdev->ctx);
62189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
62289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
62389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson/*
62489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson * IOCTL support
62589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson */
62689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic int vfio_pci_set_intx_unmask(struct vfio_pci_device *vdev,
62789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson				    unsigned index, unsigned start,
62889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson				    unsigned count, uint32_t flags, void *data)
62989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
63089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!is_intx(vdev) || start != 0 || count != 1)
63189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -EINVAL;
63289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
63389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (flags & VFIO_IRQ_SET_DATA_NONE) {
63489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		vfio_pci_intx_unmask(vdev);
63589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
63689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		uint8_t unmask = *(uint8_t *)data;
63789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if (unmask)
63889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			vfio_pci_intx_unmask(vdev);
63989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	} else if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
64089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		int32_t fd = *(int32_t *)data;
64189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if (fd >= 0)
64289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			return virqfd_enable(vdev, vfio_pci_intx_unmask_handler,
64389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson					     vfio_send_intx_eventfd, NULL,
64489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson					     &vdev->ctx[0].unmask, fd);
64589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
646b68e7fa879cd3b1126a7c455d9da1b70299efc0dAlex Williamson		virqfd_disable(vdev, &vdev->ctx[0].unmask);
64789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
64889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
64989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	return 0;
65089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
65189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
65289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic int vfio_pci_set_intx_mask(struct vfio_pci_device *vdev,
65389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson				  unsigned index, unsigned start,
65489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson				  unsigned count, uint32_t flags, void *data)
65589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
65689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!is_intx(vdev) || start != 0 || count != 1)
65789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -EINVAL;
65889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
65989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (flags & VFIO_IRQ_SET_DATA_NONE) {
66089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		vfio_pci_intx_mask(vdev);
66189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
66289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		uint8_t mask = *(uint8_t *)data;
66389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if (mask)
66489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			vfio_pci_intx_mask(vdev);
66589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	} else if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
66689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -ENOTTY; /* XXX implement me */
66789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
66889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
66989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	return 0;
67089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
67189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
67289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic int vfio_pci_set_intx_trigger(struct vfio_pci_device *vdev,
67389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson				     unsigned index, unsigned start,
67489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson				     unsigned count, uint32_t flags, void *data)
67589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
67689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (is_intx(vdev) && !count && (flags & VFIO_IRQ_SET_DATA_NONE)) {
67789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		vfio_intx_disable(vdev);
67889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return 0;
67989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
68089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
68189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!(is_intx(vdev) || is_irq_none(vdev)) || start != 0 || count != 1)
68289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -EINVAL;
68389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
68489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
68589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		int32_t fd = *(int32_t *)data;
68689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		int ret;
68789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
68889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if (is_intx(vdev))
68989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			return vfio_intx_set_signal(vdev, fd);
69089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
69189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		ret = vfio_intx_enable(vdev);
69289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if (ret)
69389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			return ret;
69489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
69589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		ret = vfio_intx_set_signal(vdev, fd);
69689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if (ret)
69789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			vfio_intx_disable(vdev);
69889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
69989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return ret;
70089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
70189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
70289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!is_intx(vdev))
70389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -EINVAL;
70489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
70589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (flags & VFIO_IRQ_SET_DATA_NONE) {
70689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		vfio_send_intx_eventfd(vdev, NULL);
70789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
70889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		uint8_t trigger = *(uint8_t *)data;
70989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if (trigger)
71089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			vfio_send_intx_eventfd(vdev, NULL);
71189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
71289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	return 0;
71389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
71489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
71589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonstatic int vfio_pci_set_msi_trigger(struct vfio_pci_device *vdev,
71689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson				    unsigned index, unsigned start,
71789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson				    unsigned count, uint32_t flags, void *data)
71889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
71989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	int i;
72089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	bool msix = (index == VFIO_PCI_MSIX_IRQ_INDEX) ? true : false;
72189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
72289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (irq_is(vdev, index) && !count && (flags & VFIO_IRQ_SET_DATA_NONE)) {
72389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		vfio_msi_disable(vdev, msix);
72489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return 0;
72589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
72689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
72789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!(irq_is(vdev, index) || is_irq_none(vdev)))
72889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -EINVAL;
72989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
73089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
73189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		int32_t *fds = data;
73289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		int ret;
73389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
73489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if (vdev->irq_type == index)
73589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			return vfio_msi_set_block(vdev, start, count,
73689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson						  fds, msix);
73789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
73889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		ret = vfio_msi_enable(vdev, start + count, msix);
73989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if (ret)
74089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			return ret;
74189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
74289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		ret = vfio_msi_set_block(vdev, start, count, fds, msix);
74389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if (ret)
74489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			vfio_msi_disable(vdev, msix);
74589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
74689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return ret;
74789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
74889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
74989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!irq_is(vdev, index) || start + count > vdev->num_ctx)
75089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -EINVAL;
75189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
75289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	for (i = start; i < start + count; i++) {
75389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if (!vdev->ctx[i].trigger)
75489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			continue;
75589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		if (flags & VFIO_IRQ_SET_DATA_NONE) {
75689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			eventfd_signal(vdev->ctx[i].trigger, 1);
75789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
75889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			uint8_t *bools = data;
75989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			if (bools[i - start])
76089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson				eventfd_signal(vdev->ctx[i].trigger, 1);
76189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		}
76289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
76389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	return 0;
76489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
76589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
766dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathilstatic int vfio_pci_set_err_trigger(struct vfio_pci_device *vdev,
767dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil				    unsigned index, unsigned start,
768dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil				    unsigned count, uint32_t flags, void *data)
769dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil{
770dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil	int32_t fd = *(int32_t *)data;
771dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil
772dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil	if ((index != VFIO_PCI_ERR_IRQ_INDEX) ||
773dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil	    !(flags & VFIO_IRQ_SET_DATA_TYPE_MASK))
774dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		return -EINVAL;
775dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil
776dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil	/* DATA_NONE/DATA_BOOL enables loopback testing */
777dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil	if (flags & VFIO_IRQ_SET_DATA_NONE) {
778dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		if (vdev->err_trigger)
779dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil			eventfd_signal(vdev->err_trigger, 1);
780dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		return 0;
781dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil	} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
782dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		uint8_t trigger = *(uint8_t *)data;
783dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		if (trigger && vdev->err_trigger)
784dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil			eventfd_signal(vdev->err_trigger, 1);
785dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		return 0;
786dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil	}
787dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil
788dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil	/* Handle SET_DATA_EVENTFD */
789dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil	if (fd == -1) {
790dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		if (vdev->err_trigger)
791dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil			eventfd_ctx_put(vdev->err_trigger);
792dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		vdev->err_trigger = NULL;
793dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		return 0;
794dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil	} else if (fd >= 0) {
795dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		struct eventfd_ctx *efdctx;
796dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		efdctx = eventfd_ctx_fdget(fd);
797dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		if (IS_ERR(efdctx))
798dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil			return PTR_ERR(efdctx);
799dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		if (vdev->err_trigger)
800dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil			eventfd_ctx_put(vdev->err_trigger);
801dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		vdev->err_trigger = efdctx;
802dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		return 0;
803dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil	} else
804dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		return -EINVAL;
805dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil}
80689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamsonint vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev, uint32_t flags,
80789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			    unsigned index, unsigned start, unsigned count,
80889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			    void *data)
80989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson{
81089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	int (*func)(struct vfio_pci_device *vdev, unsigned index,
81189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		    unsigned start, unsigned count, uint32_t flags,
81289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		    void *data) = NULL;
81389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
81489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	switch (index) {
81589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	case VFIO_PCI_INTX_IRQ_INDEX:
81689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
81789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		case VFIO_IRQ_SET_ACTION_MASK:
81889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			func = vfio_pci_set_intx_mask;
81989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			break;
82089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		case VFIO_IRQ_SET_ACTION_UNMASK:
82189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			func = vfio_pci_set_intx_unmask;
82289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			break;
82389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		case VFIO_IRQ_SET_ACTION_TRIGGER:
82489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			func = vfio_pci_set_intx_trigger;
82589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			break;
82689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		}
82789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		break;
82889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	case VFIO_PCI_MSI_IRQ_INDEX:
82989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	case VFIO_PCI_MSIX_IRQ_INDEX:
83089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
83189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		case VFIO_IRQ_SET_ACTION_MASK:
83289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		case VFIO_IRQ_SET_ACTION_UNMASK:
83389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			/* XXX Need masking support exported */
83489e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			break;
83589e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		case VFIO_IRQ_SET_ACTION_TRIGGER:
83689e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			func = vfio_pci_set_msi_trigger;
83789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson			break;
83889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		}
83989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		break;
840dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil	case VFIO_PCI_ERR_IRQ_INDEX:
841dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
842dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		case VFIO_IRQ_SET_ACTION_TRIGGER:
843dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil			if (pci_is_pcie(vdev->pdev))
844dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil				func = vfio_pci_set_err_trigger;
845dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil			break;
846dad9f8972e04cd081a028d8fb1249d746d97fc03Vijay Mohan Pandarathil		}
84789e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	}
84889e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
84989e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	if (!func)
85089e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson		return -ENOTTY;
85189e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson
85289e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson	return func(vdev, index, start, count, flags, data);
85389e1f7d4c66d85f42c3d52ea3866eb10cadf6153Alex Williamson}
854