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