xref: /freebsd/sys/compat/linuxkpi/common/include/linux/interrupt.h (revision 31ba4ce8898f9dfa5e7f054fdbc26e50a599a6e3)
1 /*-
2  * Copyright (c) 2010 Isilon Systems, Inc.
3  * Copyright (c) 2010 iX Systems, Inc.
4  * Copyright (c) 2010 Panasas, Inc.
5  * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice unmodified, this list of conditions, and the following
13  *    disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 #ifndef	_LINUX_INTERRUPT_H_
32 #define	_LINUX_INTERRUPT_H_
33 
34 #include <linux/cpu.h>
35 #include <linux/device.h>
36 #include <linux/pci.h>
37 #include <linux/irqreturn.h>
38 #include <linux/hardirq.h>
39 
40 #include <sys/param.h>
41 #include <sys/bus.h>
42 #include <sys/rman.h>
43 #include <sys/interrupt.h>
44 
45 typedef	irqreturn_t	(*irq_handler_t)(int, void *);
46 
47 #define	IRQF_SHARED	RF_SHAREABLE
48 
49 struct irq_ent {
50 	struct list_head	links;
51 	struct device	*dev;
52 	struct resource	*res;
53 	void		*arg;
54 	irqreturn_t	(*handler)(int, void *);
55 	irqreturn_t	(*thread_handler)(int, void *);
56 	void		*tag;
57 	unsigned int	irq;
58 };
59 
60 void linux_irq_handler(void *);
61 void lkpi_devm_irq_release(struct device *, void *);
62 void lkpi_irq_release(struct device *, struct irq_ent *);
63 
64 static inline int
65 linux_irq_rid(struct device *dev, unsigned int irq)
66 {
67 	/* check for MSI- or MSIX- interrupt */
68 	if (irq >= dev->irq_start && irq < dev->irq_end)
69 		return (irq - dev->irq_start + 1);
70 	else
71 		return (0);
72 }
73 
74 static inline struct irq_ent *
75 linux_irq_ent(struct device *dev, unsigned int irq)
76 {
77 	struct irq_ent *irqe;
78 
79 	list_for_each_entry(irqe, &dev->irqents, links)
80 		if (irqe->irq == irq)
81 			return (irqe);
82 
83 	return (NULL);
84 }
85 
86 static inline int
87 _request_irq(struct device *xdev, unsigned int irq,
88     irq_handler_t handler, irq_handler_t thread_handler,
89     unsigned long flags, const char *name, void *arg)
90 {
91 	struct resource *res;
92 	struct irq_ent *irqe;
93 	struct device *dev;
94 	int error;
95 	int rid;
96 
97 	dev = linux_pci_find_irq_dev(irq);
98 	if (dev == NULL)
99 		return -ENXIO;
100 	if (xdev != NULL && xdev != dev)
101 		return -ENXIO;
102 	rid = linux_irq_rid(dev, irq);
103 	res = bus_alloc_resource_any(dev->bsddev, SYS_RES_IRQ, &rid,
104 	    flags | RF_ACTIVE);
105 	if (res == NULL)
106 		return (-ENXIO);
107 	if (xdev != NULL)
108 		irqe = lkpi_devres_alloc(lkpi_devm_irq_release, sizeof(*irqe),
109 		    GFP_KERNEL | __GFP_ZERO);
110 	else
111 		irqe = kzalloc(sizeof(*irqe), GFP_KERNEL);
112 	irqe->dev = dev;
113 	irqe->res = res;
114 	irqe->arg = arg;
115 	irqe->handler = handler;
116 	irqe->thread_handler = thread_handler;
117 	irqe->irq = irq;
118 
119 	error = bus_setup_intr(dev->bsddev, res, INTR_TYPE_NET | INTR_MPSAFE,
120 	    NULL, linux_irq_handler, irqe, &irqe->tag);
121 	if (error)
122 		goto errout;
123 	list_add(&irqe->links, &dev->irqents);
124 	if (xdev != NULL)
125 		devres_add(xdev, irqe);
126 
127 	return 0;
128 
129 errout:
130 	bus_release_resource(dev->bsddev, SYS_RES_IRQ, rid, irqe->res);
131 	if (xdev != NULL)
132 		devres_free(irqe);
133 	else
134 		kfree(irqe);
135 	return (-error);
136 }
137 
138 static inline int
139 request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
140     const char *name, void *arg)
141 {
142 
143 	return (_request_irq(NULL, irq, handler, NULL, flags, name, arg));
144 }
145 
146 static inline int
147 request_threaded_irq(int irq, irq_handler_t handler,
148     irq_handler_t thread_handler, unsigned long flags,
149     const char *name, void *arg)
150 {
151 
152 	return (_request_irq(NULL, irq, handler, thread_handler,
153 	    flags, name, arg));
154 }
155 
156 static inline int
157 devm_request_threaded_irq(struct device *dev, int irq,
158     irq_handler_t handler, irq_handler_t thread_handler,
159     unsigned long flags, const char *name, void *arg)
160 {
161 
162 	return (_request_irq(dev, irq, handler, thread_handler,
163 	    flags, name, arg));
164 }
165 
166 static inline int
167 enable_irq(unsigned int irq)
168 {
169 	struct irq_ent *irqe;
170 	struct device *dev;
171 
172 	dev = linux_pci_find_irq_dev(irq);
173 	if (dev == NULL)
174 		return -EINVAL;
175 	irqe = linux_irq_ent(dev, irq);
176 	if (irqe == NULL || irqe->tag != NULL)
177 		return -EINVAL;
178 	return -bus_setup_intr(dev->bsddev, irqe->res, INTR_TYPE_NET | INTR_MPSAFE,
179 	    NULL, linux_irq_handler, irqe, &irqe->tag);
180 }
181 
182 static inline void
183 disable_irq(unsigned int irq)
184 {
185 	struct irq_ent *irqe;
186 	struct device *dev;
187 
188 	dev = linux_pci_find_irq_dev(irq);
189 	if (dev == NULL)
190 		return;
191 	irqe = linux_irq_ent(dev, irq);
192 	if (irqe == NULL)
193 		return;
194 	if (irqe->tag != NULL)
195 		bus_teardown_intr(dev->bsddev, irqe->res, irqe->tag);
196 	irqe->tag = NULL;
197 }
198 
199 static inline int
200 bind_irq_to_cpu(unsigned int irq, int cpu_id)
201 {
202 	struct irq_ent *irqe;
203 	struct device *dev;
204 
205 	dev = linux_pci_find_irq_dev(irq);
206 	if (dev == NULL)
207 		return (-ENOENT);
208 
209 	irqe = linux_irq_ent(dev, irq);
210 	if (irqe == NULL)
211 		return (-ENOENT);
212 
213 	return (-bus_bind_intr(dev->bsddev, irqe->res, cpu_id));
214 }
215 
216 static inline void
217 free_irq(unsigned int irq, void *device __unused)
218 {
219 	struct irq_ent *irqe;
220 	struct device *dev;
221 
222 	dev = linux_pci_find_irq_dev(irq);
223 	if (dev == NULL)
224 		return;
225 	irqe = linux_irq_ent(dev, irq);
226 	if (irqe == NULL)
227 		return;
228 	lkpi_irq_release(dev, irqe);
229 	kfree(irqe);
230 }
231 
232 static inline void
233 devm_free_irq(struct device *xdev, unsigned int irq, void *p)
234 {
235 	struct device *dev;
236 	struct irq_ent *irqe;
237 
238 	dev = linux_pci_find_irq_dev(irq);
239 	if (dev == NULL)
240 		return;
241 	if (xdev != dev)
242 		return;
243 	irqe = linux_irq_ent(dev, irq);
244 	if (irqe == NULL)
245 		return;
246 	lkpi_irq_release(dev, irqe);
247 	lkpi_devres_unlink(dev, irqe);
248 	lkpi_devres_free(irqe);
249 	return;
250 }
251 
252 static inline int
253 irq_set_affinity_hint(int vector, cpumask_t *mask)
254 {
255 	int error;
256 
257 	if (mask != NULL)
258 		error = intr_setaffinity(vector, CPU_WHICH_IRQ, mask);
259 	else
260 		error = intr_setaffinity(vector, CPU_WHICH_IRQ, cpuset_root);
261 
262 	return (-error);
263 }
264 
265 /*
266  * LinuxKPI tasklet support
267  */
268 typedef void tasklet_func_t(unsigned long);
269 
270 struct tasklet_struct {
271 	TAILQ_ENTRY(tasklet_struct) entry;
272 	tasklet_func_t *func;
273 	/* Our "state" implementation is different. Avoid same name as Linux. */
274 	volatile u_int tasklet_state;
275 	atomic_t count;
276 	unsigned long data;
277 };
278 
279 #define	DECLARE_TASKLET(_name, _func, _data)	\
280 struct tasklet_struct _name = { .func = (_func), .data = (_data) }
281 
282 #define	tasklet_hi_schedule(t)	tasklet_schedule(t)
283 
284 extern void tasklet_schedule(struct tasklet_struct *);
285 extern void tasklet_kill(struct tasklet_struct *);
286 extern void tasklet_init(struct tasklet_struct *, tasklet_func_t *,
287     unsigned long data);
288 extern void tasklet_enable(struct tasklet_struct *);
289 extern void tasklet_disable(struct tasklet_struct *);
290 extern void tasklet_disable_nosync(struct tasklet_struct *);
291 extern int tasklet_trylock(struct tasklet_struct *);
292 extern void tasklet_unlock(struct tasklet_struct *);
293 extern void tasklet_unlock_wait(struct tasklet_struct *ts);
294 
295 #endif	/* _LINUX_INTERRUPT_H_ */
296