1 /* 2 * Copyright (c) 2018 François Tigeot 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <linux/interrupt.h> 28 #include <linux/device.h> 29 #include <drm/drmP.h> 30 31 #include <sys/bus.h> 32 #include <bus/pci/pcivar.h> 33 34 struct irq_data { 35 unsigned int irq; 36 void *dev_id; 37 irq_handler_t handler; 38 const char *name; 39 int rid; 40 struct resource *resource; 41 void *cookiep; 42 struct lwkt_serialize irq_lock; 43 SLIST_ENTRY(irq_data) id_irq_entries; 44 }; 45 46 SLIST_HEAD(irq_data_list_head, irq_data) irq_list = SLIST_HEAD_INITIALIZER(irq_list); 47 48 /* DragonFly irq handler, used to invoke Linux ones */ 49 static void 50 linux_irq_handler(void *arg) 51 { 52 struct irq_data *irq_entry = arg; 53 54 irq_entry->handler(irq_entry->irq, irq_entry->dev_id); 55 } 56 57 /* 58 * dev is a struct drm_device* 59 * returns: zero on success, non-zero on failure 60 */ 61 int 62 request_irq(unsigned int irq, irq_handler_t handler, 63 unsigned long flags, const char *name, void *dev) 64 { 65 int error; 66 struct irq_data *irq_entry; 67 struct drm_device *ddev = dev; 68 device_t bdev = ddev->dev->bsddev; 69 70 irq_entry = kmalloc(sizeof(*irq_entry), M_DRM, M_WAITOK); 71 72 /* From drm_init_pdev() */ 73 irq_entry->rid = ddev->pdev->_irqrid; 74 irq_entry->resource = ddev->pdev->_irqr; 75 76 irq_entry->irq = irq; 77 irq_entry->dev_id = dev; 78 irq_entry->handler = handler; 79 irq_entry->name = name; 80 lwkt_serialize_init(&irq_entry->irq_lock); 81 82 error = bus_setup_intr(bdev, irq_entry->resource, INTR_MPSAFE, 83 linux_irq_handler, irq_entry, &irq_entry->cookiep, 84 &irq_entry->irq_lock); 85 if (error) { 86 kprintf("request_irq: failed in bus_setup_intr()\n"); 87 bus_release_resource(bdev, SYS_RES_IRQ, 88 irq_entry->rid, irq_entry->resource); 89 kfree(irq_entry); 90 return -error; 91 } 92 SLIST_INSERT_HEAD(&irq_list, irq_entry, id_irq_entries); 93 94 return 0; 95 } 96 97 /* dev_id is a struct drm_device* */ 98 void 99 free_irq(unsigned int irq, void *dev_id) 100 { 101 struct irq_data *irq_entry, *tmp_ie; 102 struct drm_device *ddev = dev_id; 103 device_t bsddev = ddev->dev->bsddev; 104 struct resource *res = ddev->pdev->_irqr; 105 int found = 0; 106 107 SLIST_FOREACH_MUTABLE(irq_entry, &irq_list, id_irq_entries, tmp_ie) { 108 if ((irq_entry->irq == irq) && (irq_entry->dev_id == dev_id)) { 109 found = 1; 110 break; 111 } 112 } 113 114 if (!found) { 115 kprintf("free_irq: irq %d for dev_id %p was not registered\n", 116 irq, dev_id); 117 return; 118 } 119 120 bus_teardown_intr(bsddev, res, irq_entry->cookiep); 121 bus_release_resource(bsddev, SYS_RES_IRQ, irq_entry->rid, res); 122 if (ddev->pdev->_irq_type == PCI_INTR_TYPE_MSI) 123 pci_release_msi(bsddev); 124 125 SLIST_REMOVE(&irq_list, irq_entry, irq_data, id_irq_entries); 126 kfree(irq_entry); 127 } 128