0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/eventfd.h>
0013 #include <linux/file.h>
0014 #include <linux/poll.h>
0015 #include <linux/slab.h>
0016
0017 #include "acrn_drv.h"
0018
0019 static LIST_HEAD(acrn_irqfd_clients);
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 struct hsm_irqfd {
0032 struct acrn_vm *vm;
0033 wait_queue_entry_t wait;
0034 struct work_struct shutdown;
0035 struct eventfd_ctx *eventfd;
0036 struct list_head list;
0037 poll_table pt;
0038 struct acrn_msi_entry msi;
0039 };
0040
0041 static void acrn_irqfd_inject(struct hsm_irqfd *irqfd)
0042 {
0043 struct acrn_vm *vm = irqfd->vm;
0044
0045 acrn_msi_inject(vm, irqfd->msi.msi_addr,
0046 irqfd->msi.msi_data);
0047 }
0048
0049 static void hsm_irqfd_shutdown(struct hsm_irqfd *irqfd)
0050 {
0051 u64 cnt;
0052
0053 lockdep_assert_held(&irqfd->vm->irqfds_lock);
0054
0055
0056 list_del_init(&irqfd->list);
0057 eventfd_ctx_remove_wait_queue(irqfd->eventfd, &irqfd->wait, &cnt);
0058 eventfd_ctx_put(irqfd->eventfd);
0059 kfree(irqfd);
0060 }
0061
0062 static void hsm_irqfd_shutdown_work(struct work_struct *work)
0063 {
0064 struct hsm_irqfd *irqfd;
0065 struct acrn_vm *vm;
0066
0067 irqfd = container_of(work, struct hsm_irqfd, shutdown);
0068 vm = irqfd->vm;
0069 mutex_lock(&vm->irqfds_lock);
0070 if (!list_empty(&irqfd->list))
0071 hsm_irqfd_shutdown(irqfd);
0072 mutex_unlock(&vm->irqfds_lock);
0073 }
0074
0075
0076 static int hsm_irqfd_wakeup(wait_queue_entry_t *wait, unsigned int mode,
0077 int sync, void *key)
0078 {
0079 unsigned long poll_bits = (unsigned long)key;
0080 struct hsm_irqfd *irqfd;
0081 struct acrn_vm *vm;
0082
0083 irqfd = container_of(wait, struct hsm_irqfd, wait);
0084 vm = irqfd->vm;
0085 if (poll_bits & POLLIN)
0086
0087 acrn_irqfd_inject(irqfd);
0088
0089 if (poll_bits & POLLHUP)
0090
0091 queue_work(vm->irqfd_wq, &irqfd->shutdown);
0092
0093 return 0;
0094 }
0095
0096 static void hsm_irqfd_poll_func(struct file *file, wait_queue_head_t *wqh,
0097 poll_table *pt)
0098 {
0099 struct hsm_irqfd *irqfd;
0100
0101 irqfd = container_of(pt, struct hsm_irqfd, pt);
0102 add_wait_queue(wqh, &irqfd->wait);
0103 }
0104
0105
0106
0107
0108
0109
0110 static int acrn_irqfd_assign(struct acrn_vm *vm, struct acrn_irqfd *args)
0111 {
0112 struct eventfd_ctx *eventfd = NULL;
0113 struct hsm_irqfd *irqfd, *tmp;
0114 __poll_t events;
0115 struct fd f;
0116 int ret = 0;
0117
0118 irqfd = kzalloc(sizeof(*irqfd), GFP_KERNEL);
0119 if (!irqfd)
0120 return -ENOMEM;
0121
0122 irqfd->vm = vm;
0123 memcpy(&irqfd->msi, &args->msi, sizeof(args->msi));
0124 INIT_LIST_HEAD(&irqfd->list);
0125 INIT_WORK(&irqfd->shutdown, hsm_irqfd_shutdown_work);
0126
0127 f = fdget(args->fd);
0128 if (!f.file) {
0129 ret = -EBADF;
0130 goto out;
0131 }
0132
0133 eventfd = eventfd_ctx_fileget(f.file);
0134 if (IS_ERR(eventfd)) {
0135 ret = PTR_ERR(eventfd);
0136 goto fail;
0137 }
0138
0139 irqfd->eventfd = eventfd;
0140
0141
0142
0143
0144
0145 init_waitqueue_func_entry(&irqfd->wait, hsm_irqfd_wakeup);
0146 init_poll_funcptr(&irqfd->pt, hsm_irqfd_poll_func);
0147
0148 mutex_lock(&vm->irqfds_lock);
0149 list_for_each_entry(tmp, &vm->irqfds, list) {
0150 if (irqfd->eventfd != tmp->eventfd)
0151 continue;
0152 ret = -EBUSY;
0153 mutex_unlock(&vm->irqfds_lock);
0154 goto fail;
0155 }
0156 list_add_tail(&irqfd->list, &vm->irqfds);
0157 mutex_unlock(&vm->irqfds_lock);
0158
0159
0160 events = vfs_poll(f.file, &irqfd->pt);
0161
0162 if (events & EPOLLIN)
0163 acrn_irqfd_inject(irqfd);
0164
0165 fdput(f);
0166 return 0;
0167 fail:
0168 if (eventfd && !IS_ERR(eventfd))
0169 eventfd_ctx_put(eventfd);
0170
0171 fdput(f);
0172 out:
0173 kfree(irqfd);
0174 return ret;
0175 }
0176
0177 static int acrn_irqfd_deassign(struct acrn_vm *vm,
0178 struct acrn_irqfd *args)
0179 {
0180 struct hsm_irqfd *irqfd, *tmp;
0181 struct eventfd_ctx *eventfd;
0182
0183 eventfd = eventfd_ctx_fdget(args->fd);
0184 if (IS_ERR(eventfd))
0185 return PTR_ERR(eventfd);
0186
0187 mutex_lock(&vm->irqfds_lock);
0188 list_for_each_entry_safe(irqfd, tmp, &vm->irqfds, list) {
0189 if (irqfd->eventfd == eventfd) {
0190 hsm_irqfd_shutdown(irqfd);
0191 break;
0192 }
0193 }
0194 mutex_unlock(&vm->irqfds_lock);
0195 eventfd_ctx_put(eventfd);
0196
0197 return 0;
0198 }
0199
0200 int acrn_irqfd_config(struct acrn_vm *vm, struct acrn_irqfd *args)
0201 {
0202 int ret;
0203
0204 if (args->flags & ACRN_IRQFD_FLAG_DEASSIGN)
0205 ret = acrn_irqfd_deassign(vm, args);
0206 else
0207 ret = acrn_irqfd_assign(vm, args);
0208
0209 return ret;
0210 }
0211
0212 int acrn_irqfd_init(struct acrn_vm *vm)
0213 {
0214 INIT_LIST_HEAD(&vm->irqfds);
0215 mutex_init(&vm->irqfds_lock);
0216 vm->irqfd_wq = alloc_workqueue("acrn_irqfd-%u", 0, 0, vm->vmid);
0217 if (!vm->irqfd_wq)
0218 return -ENOMEM;
0219
0220 dev_dbg(acrn_dev.this_device, "VM %u irqfd init.\n", vm->vmid);
0221 return 0;
0222 }
0223
0224 void acrn_irqfd_deinit(struct acrn_vm *vm)
0225 {
0226 struct hsm_irqfd *irqfd, *next;
0227
0228 dev_dbg(acrn_dev.this_device, "VM %u irqfd deinit.\n", vm->vmid);
0229 destroy_workqueue(vm->irqfd_wq);
0230 mutex_lock(&vm->irqfds_lock);
0231 list_for_each_entry_safe(irqfd, next, &vm->irqfds, list)
0232 hsm_irqfd_shutdown(irqfd);
0233 mutex_unlock(&vm->irqfds_lock);
0234 }