/* * VFIO platform devices interrupt handling * * Copyright (C) 2013 - Virtual Open Systems * Author: Antonios Motakis * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include #include #include "vfio_platform_private.h" static void vfio_platform_mask(struct vfio_platform_irq *irq_ctx) { unsigned long flags; spin_lock_irqsave(&irq_ctx->lock, flags); if (!irq_ctx->masked) { disable_irq_nosync(irq_ctx->hwirq); irq_ctx->masked = true; } spin_unlock_irqrestore(&irq_ctx->lock, flags); } static int vfio_platform_mask_handler(void *opaque, void *unused) { struct vfio_platform_irq *irq_ctx = opaque; vfio_platform_mask(irq_ctx); return 0; } static int vfio_platform_set_irq_mask(struct vfio_platform_device *vdev, unsigned index, unsigned start, unsigned count, uint32_t flags, void *data) { if (start != 0 || count != 1) return -EINVAL; if (!(vdev->irqs[index].flags & VFIO_IRQ_INFO_MASKABLE)) return -EINVAL; if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { int32_t fd = *(int32_t *)data; if (fd >= 0) return vfio_virqfd_enable((void *) &vdev->irqs[index], vfio_platform_mask_handler, NULL, NULL, &vdev->irqs[index].mask, fd); vfio_virqfd_disable(&vdev->irqs[index].mask); return 0; } if (flags & VFIO_IRQ_SET_DATA_NONE) { vfio_platform_mask(&vdev->irqs[index]); } else if (flags & VFIO_IRQ_SET_DATA_BOOL) { uint8_t mask = *(uint8_t *)data; if (mask) vfio_platform_mask(&vdev->irqs[index]); } return 0; } static void vfio_platform_unmask(struct vfio_platform_irq *irq_ctx) { unsigned long flags; spin_lock_irqsave(&irq_ctx->lock, flags); if (irq_ctx->masked) { enable_irq(irq_ctx->hwirq); irq_ctx->masked = false; } spin_unlock_irqrestore(&irq_ctx->lock, flags); } static int vfio_platform_unmask_handler(void *opaque, void *unused) { struct vfio_platform_irq *irq_ctx = opaque; vfio_platform_unmask(irq_ctx); return 0; } static int vfio_platform_set_irq_unmask(struct vfio_platform_device *vdev, unsigned index, unsigned start, unsigned count, uint32_t flags, void *data) { if (start != 0 || count != 1) return -EINVAL; if (!(vdev->irqs[index].flags & VFIO_IRQ_INFO_MASKABLE)) return -EINVAL; if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { int32_t fd = *(int32_t *)data; if (fd >= 0) return vfio_virqfd_enable((void *) &vdev->irqs[index], vfio_platform_unmask_handler, NULL, NULL, &vdev->irqs[index].unmask, fd); vfio_virqfd_disable(&vdev->irqs[index].unmask); return 0; } if (flags & VFIO_IRQ_SET_DATA_NONE) { vfio_platform_unmask(&vdev->irqs[index]); } else if (flags & VFIO_IRQ_SET_DATA_BOOL) { uint8_t unmask = *(uint8_t *)data; if (unmask) vfio_platform_unmask(&vdev->irqs[index]); } return 0; } static irqreturn_t vfio_automasked_irq_handler(int irq, void *dev_id) { struct vfio_platform_irq *irq_ctx = dev_id; unsigned long flags; int ret = IRQ_NONE; spin_lock_irqsave(&irq_ctx->lock, flags); if (!irq_ctx->masked) { ret = IRQ_HANDLED; /* automask maskable interrupts */ disable_irq_nosync(irq_ctx->hwirq); irq_ctx->masked = true; } spin_unlock_irqrestore(&irq_ctx->lock, flags); if (ret == IRQ_HANDLED) eventfd_signal(irq_ctx->trigger, 1); return ret; } static irqreturn_t vfio_irq_handler(int irq, void *dev_id) { struct vfio_platform_irq *irq_ctx = dev_id; eventfd_signal(irq_ctx->trigger, 1); return IRQ_HANDLED; } static int vfio_set_trigger(struct vfio_platform_device *vdev, int index, int fd, irq_handler_t handler) { struct vfio_platform_irq *irq = &vdev->irqs[index]; struct eventfd_ctx *trigger; int ret; if (irq->trigger) { irq_clear_status_flags(irq->hwirq, IRQ_NOAUTOEN); free_irq(irq->hwirq, irq); kfree(irq->name); eventfd_ctx_put(irq->trigger); irq->trigger = NULL; } if (fd < 0) /* Disable only */ return 0; irq->name = kasprintf(GFP_KERNEL, "vfio-irq[%d](%s)", irq->hwirq, vdev->name); if (!irq->name) return -ENOMEM; trigger = eventfd_ctx_fdget(fd); if (IS_ERR(trigger)) { kfree(irq->name); return PTR_ERR(trigger); } irq->trigger = trigger; irq_set_status_flags(irq->hwirq, IRQ_NOAUTOEN); ret = request_irq(irq->hwirq, handler, 0, irq->name, irq); if (ret) { kfree(irq->name); eventfd_ctx_put(trigger); irq->trigger = NULL; return ret; } if (!irq->masked) enable_irq(irq->hwirq); return 0; } static int vfio_platform_set_irq_trigger(struct vfio_platform_device *vdev, unsigned index, unsigned start, unsigned count, uint32_t flags, void *data) { struct vfio_platform_irq *irq = &vdev->irqs[index]; irq_handler_t handler; if (vdev->irqs[index].flags & VFIO_IRQ_INFO_AUTOMASKED) handler = vfio_automasked_irq_handler; else handler = vfio_irq_handler; if (!count && (flags & VFIO_IRQ_SET_DATA_NONE)) return vfio_set_trigger(vdev, index, -1, handler); if (start != 0 || count != 1) return -EINVAL; if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { int32_t fd = *(int32_t *)data; return vfio_set_trigger(vdev, index, fd, handler); } if (flags & VFIO_IRQ_SET_DATA_NONE) { handler(irq->hwirq, irq); } else if (flags & VFIO_IRQ_SET_DATA_BOOL) { uint8_t trigger = *(uint8_t *)data; if (trigger) handler(irq->hwirq, irq); } return 0; } int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev, uint32_t flags, unsigned index, unsigned start, unsigned count, void *data) { int (*func)(struct vfio_platform_device *vdev, unsigned index, unsigned start, unsigned count, uint32_t flags, void *data) = NULL; switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) { case VFIO_IRQ_SET_ACTION_MASK: func = vfio_platform_set_irq_mask; break; case VFIO_IRQ_SET_ACTION_UNMASK: func = vfio_platform_set_irq_unmask; break; case VFIO_IRQ_SET_ACTION_TRIGGER: func = vfio_platform_set_irq_trigger; break; } if (!func) return -ENOTTY; return func(vdev, index, start, count, flags, data); } int vfio_platform_irq_init(struct vfio_platform_device *vdev) { int cnt = 0, i; while (vdev->get_irq(vdev, cnt) >= 0) cnt++; vdev->irqs = kcalloc(cnt, sizeof(struct vfio_platform_irq), GFP_KERNEL); if (!vdev->irqs) return -ENOMEM; for (i = 0; i < cnt; i++) { int hwirq = vdev->get_irq(vdev, i); if (hwirq < 0) goto err; spin_lock_init(&vdev->irqs[i].lock); vdev->irqs[i].flags = VFIO_IRQ_INFO_EVENTFD; if (irq_get_trigger_type(hwirq) & IRQ_TYPE_LEVEL_MASK) vdev->irqs[i].flags |= VFIO_IRQ_INFO_MASKABLE | VFIO_IRQ_INFO_AUTOMASKED; vdev->irqs[i].count = 1; vdev->irqs[i].hwirq = hwirq; vdev->irqs[i].masked = false; } vdev->num_irqs = cnt; return 0; err: kfree(vdev->irqs); return -EINVAL; } void vfio_platform_irq_cleanup(struct vfio_platform_device *vdev) { int i; for (i = 0; i < vdev->num_irqs; i++) vfio_set_trigger(vdev, i, -1, NULL); vdev->num_irqs = 0; kfree(vdev->irqs); } rm_mode_atomic_ioctl+0x86d/0xab0 [drm] drm_ioctl+0x2b3/0x490 [drm] do_vfs_ioctl+0x69c/0x700 SyS_ioctl+0x4e/0x80 entry_SYSCALL_64_fastpath+0x13/0x94 INFO: Slab 0xffffde1f0997b080 objects=17 used=2 fp=0xffff92fb65ec2578 flags=0x200000000008101 INFO: Object 0xffff92fb65ec2578 @offset=1400 fp=0xffff92fb65ec2ae8 Redzone ffff92fb65ec2570: bb bb bb bb bb bb bb bb ........ Object ffff92fb65ec2578: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk Object ffff92fb65ec2588: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk Object ffff92fb65ec2598: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk Object ffff92fb65ec25a8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk Object ffff92fb65ec25b8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk Object ffff92fb65ec25c8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk Object ffff92fb65ec25d8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk Object ffff92fb65ec25e8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk. Redzone ffff92fb65ec25f8: bb bb bb bb bb bb bb bb ........ Padding ffff92fb65ec2738: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ CPU: 3 PID: 180 Comm: kworker/3:2 Tainted: G BU 4.10.0-rc6-patser+ #5039 Hardware name: /NUC5PPYB, BIOS PYBSWCEL.86A.0031.2015.0601.1712 06/01/2015 Workqueue: events intel_atomic_helper_free_state [i915] Call Trace: dump_stack+0x4d/0x6d print_trailer+0x20c/0x220 free_debug_processing+0x1c6/0x330 ? drm_atomic_state_default_clear+0xf7/0x1c0 [drm] __slab_free+0x48/0x2e0 ? drm_atomic_state_default_clear+0xf7/0x1c0 [drm] kfree+0x159/0x1a0 drm_atomic_state_default_clear+0xf7/0x1c0 [drm] ? drm_atomic_state_clear+0x30/0x30 [drm] intel_atomic_state_clear+0xd/0x20 [i915] drm_atomic_state_clear+0x1a/0x30 [drm] __drm_atomic_state_free+0x13/0x60 [drm] intel_atomic_helper_free_state+0x5d/0x70 [i915] process_one_work+0x260/0x4a0 worker_thread+0x2d1/0x4f0 kthread+0x127/0x130 ? process_one_work+0x4a0/0x4a0 ? kthread_stop+0x120/0x120 ret_from_fork+0x29/0x40 FIX kmalloc-128: Object at 0xffff92fb65ec2578 not freed Fixes: 3b24f7d67581 ("drm/atomic: Add struct drm_crtc_commit to track async updates") Fixes: 9626014258a5 ("drm/fence: add in-fences support") Cc: <stable@vger.kernel.org> # v4.8+ Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Gustavo Padovan <gustavo.padovan@collabora.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: http://patchwork.freedesktop.org/patch/msgid/1485854725-27640-1-git-send-email-maarten.lankhorst@linux.intel.com
Diffstat (limited to 'net/atm/addr.h')