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