1183e2373SFrançois Tigeot /* 2*0e5f0c1cSFrançois Tigeot * Copyright (c) 2018-2019 François Tigeot <ftigeot@wolfpond.org> 3183e2373SFrançois Tigeot * All rights reserved. 4183e2373SFrançois Tigeot * 5183e2373SFrançois Tigeot * Redistribution and use in source and binary forms, with or without 6183e2373SFrançois Tigeot * modification, are permitted provided that the following conditions 7183e2373SFrançois Tigeot * are met: 8183e2373SFrançois Tigeot * 1. Redistributions of source code must retain the above copyright 9183e2373SFrançois Tigeot * notice unmodified, this list of conditions, and the following 10183e2373SFrançois Tigeot * disclaimer. 11183e2373SFrançois Tigeot * 2. Redistributions in binary form must reproduce the above copyright 12183e2373SFrançois Tigeot * notice, this list of conditions and the following disclaimer in the 13183e2373SFrançois Tigeot * documentation and/or other materials provided with the distribution. 14183e2373SFrançois Tigeot * 15183e2373SFrançois Tigeot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16183e2373SFrançois Tigeot * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17183e2373SFrançois Tigeot * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18183e2373SFrançois Tigeot * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19183e2373SFrançois Tigeot * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20183e2373SFrançois Tigeot * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21183e2373SFrançois Tigeot * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22183e2373SFrançois Tigeot * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23183e2373SFrançois Tigeot * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24183e2373SFrançois Tigeot * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25183e2373SFrançois Tigeot */ 26183e2373SFrançois Tigeot 27183e2373SFrançois Tigeot #include <linux/interrupt.h> 28183e2373SFrançois Tigeot #include <linux/device.h> 29183e2373SFrançois Tigeot #include <drm/drmP.h> 30183e2373SFrançois Tigeot 31183e2373SFrançois Tigeot #include <sys/bus.h> 32183e2373SFrançois Tigeot #include <bus/pci/pcivar.h> 33183e2373SFrançois Tigeot 34183e2373SFrançois Tigeot struct irq_data { 35183e2373SFrançois Tigeot unsigned int irq; 36183e2373SFrançois Tigeot void *dev_id; 37183e2373SFrançois Tigeot irq_handler_t handler; 38183e2373SFrançois Tigeot const char *name; 39183e2373SFrançois Tigeot int rid; 40183e2373SFrançois Tigeot struct resource *resource; 41183e2373SFrançois Tigeot void *cookiep; 42183e2373SFrançois Tigeot struct lwkt_serialize irq_lock; 43183e2373SFrançois Tigeot SLIST_ENTRY(irq_data) id_irq_entries; 44183e2373SFrançois Tigeot }; 45183e2373SFrançois Tigeot 46*0e5f0c1cSFrançois Tigeot struct lock irqdata_lock = LOCK_INITIALIZER("dlidl", 0, LK_CANRECURSE); 47*0e5f0c1cSFrançois Tigeot 48183e2373SFrançois Tigeot SLIST_HEAD(irq_data_list_head, irq_data) irq_list = SLIST_HEAD_INITIALIZER(irq_list); 49183e2373SFrançois Tigeot 50183e2373SFrançois Tigeot /* DragonFly irq handler, used to invoke Linux ones */ 51183e2373SFrançois Tigeot static void 52183e2373SFrançois Tigeot linux_irq_handler(void *arg) 53183e2373SFrançois Tigeot { 54183e2373SFrançois Tigeot struct irq_data *irq_entry = arg; 55183e2373SFrançois Tigeot 56183e2373SFrançois Tigeot irq_entry->handler(irq_entry->irq, irq_entry->dev_id); 57183e2373SFrançois Tigeot } 58183e2373SFrançois Tigeot 59183e2373SFrançois Tigeot /* 60183e2373SFrançois Tigeot * dev is a struct drm_device* 61183e2373SFrançois Tigeot * returns: zero on success, non-zero on failure 62183e2373SFrançois Tigeot */ 63183e2373SFrançois Tigeot int 64183e2373SFrançois Tigeot request_irq(unsigned int irq, irq_handler_t handler, 65183e2373SFrançois Tigeot unsigned long flags, const char *name, void *dev) 66183e2373SFrançois Tigeot { 67183e2373SFrançois Tigeot int error; 68183e2373SFrançois Tigeot struct irq_data *irq_entry; 69183e2373SFrançois Tigeot struct drm_device *ddev = dev; 70183e2373SFrançois Tigeot device_t bdev = ddev->dev->bsddev; 71183e2373SFrançois Tigeot 72183e2373SFrançois Tigeot irq_entry = kmalloc(sizeof(*irq_entry), M_DRM, M_WAITOK); 73183e2373SFrançois Tigeot 74183e2373SFrançois Tigeot /* From drm_init_pdev() */ 75183e2373SFrançois Tigeot irq_entry->rid = ddev->pdev->_irqrid; 76183e2373SFrançois Tigeot irq_entry->resource = ddev->pdev->_irqr; 77183e2373SFrançois Tigeot 78183e2373SFrançois Tigeot irq_entry->irq = irq; 79183e2373SFrançois Tigeot irq_entry->dev_id = dev; 80183e2373SFrançois Tigeot irq_entry->handler = handler; 81183e2373SFrançois Tigeot irq_entry->name = name; 82183e2373SFrançois Tigeot lwkt_serialize_init(&irq_entry->irq_lock); 83183e2373SFrançois Tigeot 84183e2373SFrançois Tigeot error = bus_setup_intr(bdev, irq_entry->resource, INTR_MPSAFE, 85183e2373SFrançois Tigeot linux_irq_handler, irq_entry, &irq_entry->cookiep, 86183e2373SFrançois Tigeot &irq_entry->irq_lock); 87183e2373SFrançois Tigeot if (error) { 88183e2373SFrançois Tigeot kprintf("request_irq: failed in bus_setup_intr()\n"); 89183e2373SFrançois Tigeot bus_release_resource(bdev, SYS_RES_IRQ, 90183e2373SFrançois Tigeot irq_entry->rid, irq_entry->resource); 91183e2373SFrançois Tigeot kfree(irq_entry); 92183e2373SFrançois Tigeot return -error; 93183e2373SFrançois Tigeot } 94*0e5f0c1cSFrançois Tigeot lockmgr(&irqdata_lock, LK_EXCLUSIVE); 95183e2373SFrançois Tigeot SLIST_INSERT_HEAD(&irq_list, irq_entry, id_irq_entries); 96*0e5f0c1cSFrançois Tigeot lockmgr(&irqdata_lock, LK_RELEASE); 97183e2373SFrançois Tigeot 98183e2373SFrançois Tigeot return 0; 99183e2373SFrançois Tigeot } 100183e2373SFrançois Tigeot 101183e2373SFrançois Tigeot /* dev_id is a struct drm_device* */ 102183e2373SFrançois Tigeot void 103183e2373SFrançois Tigeot free_irq(unsigned int irq, void *dev_id) 104183e2373SFrançois Tigeot { 105183e2373SFrançois Tigeot struct irq_data *irq_entry, *tmp_ie; 106183e2373SFrançois Tigeot struct drm_device *ddev = dev_id; 107183e2373SFrançois Tigeot device_t bsddev = ddev->dev->bsddev; 108183e2373SFrançois Tigeot struct resource *res = ddev->pdev->_irqr; 109183e2373SFrançois Tigeot int found = 0; 110183e2373SFrançois Tigeot 111183e2373SFrançois Tigeot SLIST_FOREACH_MUTABLE(irq_entry, &irq_list, id_irq_entries, tmp_ie) { 112183e2373SFrançois Tigeot if ((irq_entry->irq == irq) && (irq_entry->dev_id == dev_id)) { 113183e2373SFrançois Tigeot found = 1; 114183e2373SFrançois Tigeot break; 115183e2373SFrançois Tigeot } 116183e2373SFrançois Tigeot } 117183e2373SFrançois Tigeot 118183e2373SFrançois Tigeot if (!found) { 119183e2373SFrançois Tigeot kprintf("free_irq: irq %d for dev_id %p was not registered\n", 120183e2373SFrançois Tigeot irq, dev_id); 121183e2373SFrançois Tigeot return; 122183e2373SFrançois Tigeot } 123183e2373SFrançois Tigeot 124183e2373SFrançois Tigeot bus_teardown_intr(bsddev, res, irq_entry->cookiep); 125183e2373SFrançois Tigeot bus_release_resource(bsddev, SYS_RES_IRQ, irq_entry->rid, res); 126183e2373SFrançois Tigeot if (ddev->pdev->_irq_type == PCI_INTR_TYPE_MSI) 127183e2373SFrançois Tigeot pci_release_msi(bsddev); 128183e2373SFrançois Tigeot 129*0e5f0c1cSFrançois Tigeot lockmgr(&irqdata_lock, LK_EXCLUSIVE); 130183e2373SFrançois Tigeot SLIST_REMOVE(&irq_list, irq_entry, irq_data, id_irq_entries); 131*0e5f0c1cSFrançois Tigeot lockmgr(&irqdata_lock, LK_RELEASE); 132183e2373SFrançois Tigeot kfree(irq_entry); 133183e2373SFrançois Tigeot } 134