interrupt.h revision 310250
1216115Slstewart/*-
2216115Slstewart * Copyright (c) 2010 Isilon Systems, Inc.
3216115Slstewart * Copyright (c) 2010 iX Systems, Inc.
4216115Slstewart * Copyright (c) 2010 Panasas, Inc.
5216115Slstewart * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
6216115Slstewart * All rights reserved.
7216115Slstewart *
8216115Slstewart * Redistribution and use in source and binary forms, with or without
9220560Slstewart * modification, are permitted provided that the following conditions
10220560Slstewart * are met:
11220560Slstewart * 1. Redistributions of source code must retain the above copyright
12216115Slstewart *    notice unmodified, this list of conditions, and the following
13216115Slstewart *    disclaimer.
14216115Slstewart * 2. Redistributions in binary form must reproduce the above copyright
15216115Slstewart *    notice, this list of conditions and the following disclaimer in the
16216115Slstewart *    documentation and/or other materials provided with the distribution.
17216115Slstewart *
18216115Slstewart * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19216115Slstewart * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20216115Slstewart * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21216115Slstewart * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22216115Slstewart * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23216115Slstewart * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24216115Slstewart * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25216115Slstewart * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26216115Slstewart * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27216115Slstewart * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28216115Slstewart *
29216115Slstewart * $FreeBSD: stable/11/sys/compat/linuxkpi/common/include/linux/interrupt.h 310250 2016-12-19 09:47:34Z hselasky $
30216115Slstewart */
31216115Slstewart#ifndef	_LINUX_INTERRUPT_H_
32216115Slstewart#define	_LINUX_INTERRUPT_H_
33216115Slstewart
34216115Slstewart#include <linux/device.h>
35216115Slstewart#include <linux/pci.h>
36216115Slstewart
37216115Slstewart#include <sys/bus.h>
38216115Slstewart#include <sys/rman.h>
39216115Slstewart
40216115Slstewarttypedef	irqreturn_t	(*irq_handler_t)(int, void *);
41216115Slstewart
42216115Slstewart#define	IRQ_RETVAL(x)	((x) != IRQ_NONE)
43220560Slstewart
44220560Slstewart#define	IRQF_SHARED	RF_SHAREABLE
45220560Slstewart
46220560Slstewartstruct irq_ent {
47216115Slstewart	struct list_head	links;
48216115Slstewart	struct device	*dev;
49216115Slstewart	struct resource	*res;
50216115Slstewart	void		*arg;
51216115Slstewart	irqreturn_t	(*handler)(int, void *);
52216115Slstewart	void		*tag;
53216115Slstewart	unsigned int	irq;
54216115Slstewart};
55216115Slstewart
56216115Slstewartstatic inline int
57216115Slstewartlinux_irq_rid(struct device *dev, unsigned int irq)
58216115Slstewart{
59216115Slstewart	if (irq == dev->irq)
60216115Slstewart		return (0);
61216115Slstewart	return irq - dev->msix + 1;
62216115Slstewart}
63216115Slstewart
64216115Slstewartextern void linux_irq_handler(void *);
65216115Slstewart
66216115Slstewartstatic inline struct irq_ent *
67216115Slstewartlinux_irq_ent(struct device *dev, unsigned int irq)
68216115Slstewart{
69216115Slstewart	struct irq_ent *irqe;
70216115Slstewart
71216115Slstewart	list_for_each_entry(irqe, &dev->irqents, links)
72216115Slstewart		if (irqe->irq == irq)
73216115Slstewart			return (irqe);
74216115Slstewart
75216115Slstewart	return (NULL);
76216115Slstewart}
77216115Slstewart
78216115Slstewartstatic inline int
79216115Slstewartrequest_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
80216115Slstewart    const char *name, void *arg)
81216115Slstewart{
82216115Slstewart	struct resource *res;
83216115Slstewart	struct irq_ent *irqe;
84216115Slstewart	struct device *dev;
85216115Slstewart	int error;
86216115Slstewart	int rid;
87216115Slstewart
88216115Slstewart	dev = linux_pci_find_irq_dev(irq);
89216115Slstewart	if (dev == NULL)
90216115Slstewart		return -ENXIO;
91216115Slstewart	rid = linux_irq_rid(dev, irq);
92216115Slstewart	res = bus_alloc_resource_any(dev->bsddev, SYS_RES_IRQ, &rid,
93216115Slstewart	    flags | RF_ACTIVE);
94216115Slstewart	if (res == NULL)
95216115Slstewart		return (-ENXIO);
96216115Slstewart	irqe = kmalloc(sizeof(*irqe), GFP_KERNEL);
97216115Slstewart	irqe->dev = dev;
98216115Slstewart	irqe->res = res;
99216115Slstewart	irqe->arg = arg;
100216115Slstewart	irqe->handler = handler;
101216115Slstewart	irqe->irq = irq;
102216115Slstewart	error = bus_setup_intr(dev->bsddev, res, INTR_TYPE_NET | INTR_MPSAFE,
103216115Slstewart	    NULL, linux_irq_handler, irqe, &irqe->tag);
104216115Slstewart	if (error) {
105216115Slstewart		bus_release_resource(dev->bsddev, SYS_RES_IRQ, rid, irqe->res);
106216115Slstewart		kfree(irqe);
107216115Slstewart		return (-error);
108216115Slstewart	}
109216115Slstewart	list_add(&irqe->links, &dev->irqents);
110216115Slstewart
111216115Slstewart	return 0;
112216115Slstewart}
113216115Slstewart
114216115Slstewartstatic inline int
115216115Slstewartbind_irq_to_cpu(unsigned int irq, int cpu_id)
116216115Slstewart{
117216115Slstewart	struct irq_ent *irqe;
118216115Slstewart	struct device *dev;
119216115Slstewart
120216115Slstewart	dev = linux_pci_find_irq_dev(irq);
121216115Slstewart	if (dev == NULL)
122216115Slstewart		return (-ENOENT);
123216115Slstewart
124216115Slstewart	irqe = linux_irq_ent(dev, irq);
125216115Slstewart	if (irqe == NULL)
126216115Slstewart		return (-ENOENT);
127216115Slstewart
128216115Slstewart	return (-bus_bind_intr(dev->bsddev, irqe->res, cpu_id));
129216115Slstewart}
130216115Slstewart
131216115Slstewartstatic inline void
132216115Slstewartfree_irq(unsigned int irq, void *device)
133216115Slstewart{
134216115Slstewart	struct irq_ent *irqe;
135216115Slstewart	struct device *dev;
136216115Slstewart	int rid;
137216115Slstewart
138216115Slstewart	dev = linux_pci_find_irq_dev(irq);
139216115Slstewart	if (dev == NULL)
140216115Slstewart		return;
141216115Slstewart	rid = linux_irq_rid(dev, irq);
142216115Slstewart	irqe = linux_irq_ent(dev, irq);
143216115Slstewart	if (irqe == NULL)
144216115Slstewart		return;
145216115Slstewart	bus_teardown_intr(dev->bsddev, irqe->res, irqe->tag);
146216115Slstewart	bus_release_resource(dev->bsddev, SYS_RES_IRQ, rid, irqe->res);
147216115Slstewart	list_del(&irqe->links);
148216115Slstewart	kfree(irqe);
149216115Slstewart}
150216115Slstewart
151216115Slstewart#endif	/* _LINUX_INTERRUPT_H_ */
152216115Slstewart