/* * VFIO generic eventfd code for IRQFD support. * Derived from drivers/vfio/pci/vfio_pci_intrs.c * * Copyright (C) 2012 Red Hat, Inc. All rights reserved. * Author: Alex Williamson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include #include #include #include #include #define DRIVER_VERSION "0.1" #define DRIVER_AUTHOR "Alex Williamson " #define DRIVER_DESC "IRQFD support for VFIO bus drivers" static struct workqueue_struct *vfio_irqfd_cleanup_wq; static DEFINE_SPINLOCK(virqfd_lock); static int __init vfio_virqfd_init(void) { vfio_irqfd_cleanup_wq = create_singlethread_workqueue("vfio-irqfd-cleanup"); if (!vfio_irqfd_cleanup_wq) return -ENOMEM; return 0; } static void __exit vfio_virqfd_exit(void) { destroy_workqueue(vfio_irqfd_cleanup_wq); } static void virqfd_deactivate(struct virqfd *virqfd) { queue_work(vfio_irqfd_cleanup_wq, &virqfd->shutdown); } static int virqfd_wakeup(wait_queue_t *wait, unsigned mode, int sync, void *key) { struct virqfd *virqfd = container_of(wait, struct virqfd, wait); unsigned long flags = (unsigned long)key; if (flags & POLLIN) { /* An event has been signaled, call function */ if ((!virqfd->handler || virqfd->handler(virqfd->opaque, virqfd->data)) && virqfd->thread) schedule_work(&virqfd->inject); } if (flags & POLLHUP) { unsigned long flags; spin_lock_irqsave(&virqfd_lock, flags); /* * The eventfd is closing, if the virqfd has not yet been * queued for release, as determined by testing whether the * virqfd pointer to it is still valid, queue it now. As * with kvm irqfds, we know we won't race against the virqfd * going away because we hold the lock to get here. */ if (*(virqfd->pvirqfd) == virqfd) { *(virqfd->pvirqfd) = NULL; virqfd_deactivate(virqfd); } spin_unlock_irqrestore(&virqfd_lock, flags); } return 0; } static void virqfd_ptable_queue_proc(struct file *file, wait_queue_head_t *wqh, poll_table *pt) { struct virqfd *virqfd = container_of(pt, struct virqfd, pt); add_wait_queue(wqh, &virqfd->wait); } static void virqfd_shutdown(struct work_struct *work) { struct virqfd *virqfd = container_of(work, struct virqfd, shutdown); u64 cnt; eventfd_ctx_remove_wait_queue(virqfd->eventfd, &virqfd->wait, &cnt); flush_work(&virqfd->inject); eventfd_ctx_put(virqfd->eventfd); kfree(virqfd); } static void virqfd_inject(struct work_struct *work) { struct virqfd *virqfd = container_of(work, struct virqfd, inject); if (virqfd->thread) virqfd->thread(virqfd->opaque, virqfd->data); } int vfio_virqfd_enable(void *opaque, int (*handler)(void *, void *), void (*thread)(void *, void *), void *data, struct virqfd **pvirqfd, int fd) { struct fd irqfd; struct eventfd_ctx *ctx; struct virqfd *virqfd; int ret = 0; unsigned int events; virqfd = kzalloc(sizeof(*virqfd), GFP_KERNEL); if (!virqfd) return -ENOMEM; virqfd->pvirqfd = pvirqfd; virqfd->opaque = opaque; virqfd->handler = handler; virqfd->thread = thread; virqfd->data = data; INIT_WORK(&virqfd->shutdown, virqfd_shutdown); INIT_WORK(&virqfd->inject, virqfd_inject); irqfd = fdget(fd); if (!irqfd.file) { ret = -EBADF; goto err_fd; } ctx = eventfd_ctx_fileget(irqfd.file); if (IS_ERR(ctx)) { ret = PTR_ERR(ctx); goto err_ctx; } virqfd->eventfd = ctx; /* * virqfds can be released by closing the eventfd or directly * through ioctl. These are both done through a workqueue, so * we update the pointer to the virqfd under lock to avoid * pushing multiple jobs to release the same virqfd. */ spin_lock_irq(&virqfd_lock); if (*pvirqfd) { spin_unlock_irq(&virqfd_lock); ret = -EBUSY; goto err_busy; } *pvirqfd = virqfd; spin_unlock_irq(&virqfd_lock); /* * Install our own custom wake-up handling so we are notified via * a callback whenever someone signals the underlying eventfd. */ init_waitqueue_func_entry(&virqfd->wait, virqfd_wakeup); init_poll_funcptr(&virqfd->pt, virqfd_ptable_queue_proc); events = irqfd.file->f_op->poll(irqfd.file, &virqfd->pt); /* * Check if there was an event already pending on the eventfd * before we registered and trigger it as if we didn't miss it. */ if (events & POLLIN) { if ((!handler || handler(opaque, data)) && thread) schedule_work(&virqfd->inject); } /* * Do not drop the file until the irqfd is fully initialized, * otherwise we might race against the POLLHUP. */ fdput(irqfd); return 0; err_busy: eventfd_ctx_put(ctx); err_ctx: fdput(irqfd); err_fd: kfree(virqfd); return ret; } EXPORT_SYMBOL_GPL(vfio_virqfd_enable); void vfio_virqfd_disable(struct virqfd **pvirqfd) { unsigned long flags; spin_lock_irqsave(&virqfd_lock, flags); if (*pvirqfd) { virqfd_deactivate(*pvirqfd); *pvirqfd = NULL; } spin_unlock_irqrestore(&virqfd_lock, flags); /* * Block until we know all outstanding shutdown jobs have completed. * Even if we don't queue the job, flush the wq to be sure it's * been released. */ flush_workqueue(vfio_irqfd_cleanup_wq); } EXPORT_SYMBOL_GPL(vfio_virqfd_disable); module_init(vfio_virqfd_init); module_exit(vfio_virqfd_exit); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); /usb/6fire/firmware.h?id=4759d386d55fef452d692bf101167914437e848e'>sound/usb/6fire/firmware.h parent238d1d0f79f619d75c2cc741d6770fb0986aef24 (diff)parent1db175428ee374489448361213e9c3b749d14900 (diff)
Merge branch 'libnvdimm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
Pull DAX updates from Dan Williams: "The completion of Jan's DAX work for 4.10. As I mentioned in the libnvdimm-for-4.10 pull request, these are some final fixes for the DAX dirty-cacheline-tracking invalidation work that was merged through the -mm, ext4, and xfs trees in -rc1. These patches were prepared prior to the merge window, but we waited for 4.10-rc1 to have a stable merge base after all the prerequisites were merged. Quoting Jan on the overall changes in these patches: "So I'd like all these 6 patches to go for rc2. The first three patches fix invalidation of exceptional DAX entries (a bug which is there for a long time) - without these patches data loss can occur on power failure even though user called fsync(2). The other three patches change locking of DAX faults so that ->iomap_begin() is called in a more relaxed locking context and we are safe to start a transaction there for ext4" These have received a build success notification from the kbuild robot, and pass the latest libnvdimm unit tests. There have not been any -next releases since -rc1, so they have not appeared there" * 'libnvdimm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm: ext4: Simplify DAX fault path dax: Call ->iomap_begin without entry lock during dax fault dax: Finish fault completely when loading holes dax: Avoid page invalidation races and unnecessary radix tree traversals mm: Invalidate DAX radix tree entries only if appropriate ext2: Return BH_New buffers for zeroed blocks
Diffstat (limited to 'sound/usb/6fire/firmware.h')