2 * Copyright (c) 2018-2019 François Tigeot <ftigeot@wolfpond.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
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.
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.
27 #include <linux/interrupt.h>
28 #include <linux/device.h>
32 #include <bus/pci/pcivar.h>
37 irq_handler_t handler
;
40 struct resource
*resource
;
42 struct lwkt_serialize irq_lock
;
43 SLIST_ENTRY(irq_data
) id_irq_entries
;
46 struct lock irqdata_lock
= LOCK_INITIALIZER("dlidl", 0, LK_CANRECURSE
);
48 SLIST_HEAD(irq_data_list_head
, irq_data
) irq_list
= SLIST_HEAD_INITIALIZER(irq_list
);
50 /* DragonFly irq handler, used to invoke Linux ones */
52 linux_irq_handler(void *arg
)
54 struct irq_data
*irq_entry
= arg
;
56 irq_entry
->handler(irq_entry
->irq
, irq_entry
->dev_id
);
60 * dev is a struct drm_device*
61 * returns: zero on success, non-zero on failure
64 request_irq(unsigned int irq
, irq_handler_t handler
,
65 unsigned long flags
, const char *name
, void *dev
)
68 struct irq_data
*irq_entry
;
69 struct drm_device
*ddev
= dev
;
70 device_t bdev
= ddev
->dev
->bsddev
;
72 irq_entry
= kmalloc(sizeof(*irq_entry
), M_DRM
, M_WAITOK
);
74 /* From drm_init_pdev() */
75 irq_entry
->rid
= ddev
->pdev
->_irqrid
;
76 irq_entry
->resource
= ddev
->pdev
->_irqr
;
79 irq_entry
->dev_id
= dev
;
80 irq_entry
->handler
= handler
;
81 irq_entry
->name
= name
;
82 lwkt_serialize_init(&irq_entry
->irq_lock
);
84 error
= bus_setup_intr(bdev
, irq_entry
->resource
, INTR_MPSAFE
,
85 linux_irq_handler
, irq_entry
, &irq_entry
->cookiep
,
86 &irq_entry
->irq_lock
);
88 kprintf("request_irq: failed in bus_setup_intr()\n");
89 bus_release_resource(bdev
, SYS_RES_IRQ
,
90 irq_entry
->rid
, irq_entry
->resource
);
94 lockmgr(&irqdata_lock
, LK_EXCLUSIVE
);
95 SLIST_INSERT_HEAD(&irq_list
, irq_entry
, id_irq_entries
);
96 lockmgr(&irqdata_lock
, LK_RELEASE
);
101 /* dev_id is a struct drm_device* */
103 free_irq(unsigned int irq
, void *dev_id
)
105 struct irq_data
*irq_entry
, *tmp_ie
;
106 struct drm_device
*ddev
= dev_id
;
107 device_t bsddev
= ddev
->dev
->bsddev
;
108 struct resource
*res
= ddev
->pdev
->_irqr
;
111 SLIST_FOREACH_MUTABLE(irq_entry
, &irq_list
, id_irq_entries
, tmp_ie
) {
112 if ((irq_entry
->irq
== irq
) && (irq_entry
->dev_id
== dev_id
)) {
119 kprintf("free_irq: irq %d for dev_id %p was not registered\n",
124 bus_teardown_intr(bsddev
, res
, irq_entry
->cookiep
);
125 bus_release_resource(bsddev
, SYS_RES_IRQ
, irq_entry
->rid
, res
);
126 if (ddev
->pdev
->_irq_type
== PCI_INTR_TYPE_MSI
)
127 pci_release_msi(bsddev
);
129 lockmgr(&irqdata_lock
, LK_EXCLUSIVE
);
130 SLIST_REMOVE(&irq_list
, irq_entry
, irq_data
, id_irq_entries
);
131 lockmgr(&irqdata_lock
, LK_RELEASE
);
136 disable_irq(unsigned int irq
)
138 struct irq_data
*irq_entry
;
139 struct drm_device
*ddev
;
142 SLIST_FOREACH(irq_entry
, &irq_list
, id_irq_entries
) {
143 if (irq_entry
->irq
== irq
)
147 kprintf("disabling irq %d\n", irq
);
149 ddev
= irq_entry
->dev_id
;
150 bsddev
= ddev
->dev
->bsddev
;
151 bus_teardown_intr(bsddev
, irq_entry
->resource
, irq_entry
->cookiep
);
155 enable_irq(unsigned int irq
)
157 struct irq_data
*irq_entry
;
158 struct drm_device
*ddev
;
161 SLIST_FOREACH(irq_entry
, &irq_list
, id_irq_entries
) {
162 if (irq_entry
->irq
== irq
)
166 kprintf("enabling irq %d\n", irq
);
168 ddev
= irq_entry
->dev_id
;
169 bsddev
= ddev
->dev
->bsddev
;
170 bus_setup_intr(bsddev
, irq_entry
->resource
, INTR_MPSAFE
,
171 linux_irq_handler
, irq_entry
, &irq_entry
->cookiep
,
172 &irq_entry
->irq_lock
);