Changeset View
Changeset View
Standalone View
Standalone View
sys/compat/linuxkpi/common/src/linux_interrupt.c
- This file was copied from sys/compat/linuxkpi/common/include/linux/interrupt.h.
Show All 22 Lines | |||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
* | * | ||||
* $FreeBSD$ | * $FreeBSD$ | ||||
*/ | */ | ||||
#ifndef _LINUX_INTERRUPT_H_ | |||||
#define _LINUX_INTERRUPT_H_ | |||||
#include <linux/cpu.h> | |||||
#include <linux/device.h> | #include <linux/device.h> | ||||
#include <linux/interrupt.h> | |||||
#include <linux/pci.h> | #include <linux/pci.h> | ||||
#include <linux/irqreturn.h> | |||||
#include <linux/hardirq.h> | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/rman.h> | #include <sys/rman.h> | ||||
#include <sys/interrupt.h> | #include <sys/interrupt.h> | ||||
typedef irqreturn_t (*irq_handler_t)(int, void *); | #undef resource | ||||
#define IRQF_SHARED RF_SHAREABLE | |||||
struct irq_ent { | struct irq_ent { | ||||
struct list_head links; | struct list_head links; | ||||
struct device *dev; | struct device *dev; | ||||
struct resource *res; | struct resource *res; | ||||
void *arg; | void *arg; | ||||
irqreturn_t (*handler)(int, void *); | irqreturn_t (*handler)(int, void *); | ||||
irqreturn_t (*thread_handler)(int, void *); | irqreturn_t (*thread_handler)(int, void *); | ||||
void *tag; | void *tag; | ||||
unsigned int irq; | unsigned int irq; | ||||
}; | }; | ||||
void linux_irq_handler(void *); | |||||
void lkpi_devm_irq_release(struct device *, void *); | |||||
void lkpi_irq_release(struct device *, struct irq_ent *); | |||||
static inline int | static inline int | ||||
linux_irq_rid(struct device *dev, unsigned int irq) | lkpi_irq_rid(struct device *dev, unsigned int irq) | ||||
{ | { | ||||
/* check for MSI- or MSIX- interrupt */ | /* check for MSI- or MSIX- interrupt */ | ||||
if (irq >= dev->irq_start && irq < dev->irq_end) | if (irq >= dev->irq_start && irq < dev->irq_end) | ||||
return (irq - dev->irq_start + 1); | return (irq - dev->irq_start + 1); | ||||
else | else | ||||
return (0); | return (0); | ||||
} | } | ||||
static inline struct irq_ent * | static inline struct irq_ent * | ||||
linux_irq_ent(struct device *dev, unsigned int irq) | lkpi_irq_ent(struct device *dev, unsigned int irq) | ||||
{ | { | ||||
struct irq_ent *irqe; | struct irq_ent *irqe; | ||||
list_for_each_entry(irqe, &dev->irqents, links) | list_for_each_entry(irqe, &dev->irqents, links) | ||||
if (irqe->irq == irq) | if (irqe->irq == irq) | ||||
return (irqe); | return (irqe); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
static inline int | void | ||||
_request_irq(struct device *xdev, unsigned int irq, | linux_irq_handler(void *ent) | ||||
{ | |||||
struct irq_ent *irqe; | |||||
if (linux_set_current_flags(curthread, M_NOWAIT)) | |||||
return; | |||||
irqe = ent; | |||||
if (irqe->handler(irqe->irq, irqe->arg) == IRQ_WAKE_THREAD && | |||||
irqe->thread_handler != NULL) { | |||||
THREAD_SLEEPING_OK(); | |||||
irqe->thread_handler(irqe->irq, irqe->arg); | |||||
THREAD_NO_SLEEPING(); | |||||
} | |||||
} | |||||
void | |||||
lkpi_irq_release(struct device *dev, struct irq_ent *irqe) | |||||
{ | |||||
if (irqe->tag != NULL) | |||||
bus_teardown_intr(dev->bsddev, irqe->res, irqe->tag); | |||||
if (irqe->res != NULL) | |||||
bus_release_resource(dev->bsddev, SYS_RES_IRQ, | |||||
rman_get_rid(irqe->res), irqe->res); | |||||
list_del(&irqe->links); | |||||
} | |||||
void | |||||
lkpi_devm_irq_release(struct device *dev, void *p) | |||||
{ | |||||
struct irq_ent *irqe; | |||||
if (dev == NULL || p == NULL) | |||||
return; | |||||
irqe = p; | |||||
lkpi_irq_release(dev, irqe); | |||||
} | |||||
int | |||||
lkpi_request_irq(struct device *xdev, unsigned int irq, | |||||
irq_handler_t handler, irq_handler_t thread_handler, | irq_handler_t handler, irq_handler_t thread_handler, | ||||
unsigned long flags, const char *name, void *arg) | unsigned long flags, const char *name, void *arg) | ||||
{ | { | ||||
struct resource *res; | struct resource *res; | ||||
struct irq_ent *irqe; | struct irq_ent *irqe; | ||||
struct device *dev; | struct device *dev; | ||||
int error; | int error; | ||||
int rid; | int rid; | ||||
dev = linux_pci_find_irq_dev(irq); | dev = linux_pci_find_irq_dev(irq); | ||||
if (dev == NULL) | if (dev == NULL) | ||||
return -ENXIO; | return -ENXIO; | ||||
if (xdev != NULL && xdev != dev) | if (xdev != NULL && xdev != dev) | ||||
return -ENXIO; | return -ENXIO; | ||||
rid = linux_irq_rid(dev, irq); | rid = lkpi_irq_rid(dev, irq); | ||||
res = bus_alloc_resource_any(dev->bsddev, SYS_RES_IRQ, &rid, | res = bus_alloc_resource_any(dev->bsddev, SYS_RES_IRQ, &rid, | ||||
flags | RF_ACTIVE); | flags | RF_ACTIVE); | ||||
if (res == NULL) | if (res == NULL) | ||||
return (-ENXIO); | return (-ENXIO); | ||||
if (xdev != NULL) | if (xdev != NULL) | ||||
irqe = lkpi_devres_alloc(lkpi_devm_irq_release, sizeof(*irqe), | irqe = lkpi_devres_alloc(lkpi_devm_irq_release, sizeof(*irqe), | ||||
GFP_KERNEL | __GFP_ZERO); | GFP_KERNEL | __GFP_ZERO); | ||||
else | else | ||||
Show All 19 Lines | errout: | ||||
bus_release_resource(dev->bsddev, SYS_RES_IRQ, rid, irqe->res); | bus_release_resource(dev->bsddev, SYS_RES_IRQ, rid, irqe->res); | ||||
if (xdev != NULL) | if (xdev != NULL) | ||||
devres_free(irqe); | devres_free(irqe); | ||||
else | else | ||||
kfree(irqe); | kfree(irqe); | ||||
return (-error); | return (-error); | ||||
} | } | ||||
static inline int | int | ||||
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, | lkpi_enable_irq(unsigned int irq) | ||||
const char *name, void *arg) | |||||
{ | { | ||||
return (_request_irq(NULL, irq, handler, NULL, flags, name, arg)); | |||||
} | |||||
static inline int | |||||
request_threaded_irq(int irq, irq_handler_t handler, | |||||
irq_handler_t thread_handler, unsigned long flags, | |||||
const char *name, void *arg) | |||||
{ | |||||
return (_request_irq(NULL, irq, handler, thread_handler, | |||||
flags, name, arg)); | |||||
} | |||||
static inline int | |||||
devm_request_threaded_irq(struct device *dev, int irq, | |||||
irq_handler_t handler, irq_handler_t thread_handler, | |||||
unsigned long flags, const char *name, void *arg) | |||||
{ | |||||
return (_request_irq(dev, irq, handler, thread_handler, | |||||
flags, name, arg)); | |||||
} | |||||
static inline int | |||||
enable_irq(unsigned int irq) | |||||
{ | |||||
struct irq_ent *irqe; | struct irq_ent *irqe; | ||||
struct device *dev; | struct device *dev; | ||||
dev = linux_pci_find_irq_dev(irq); | dev = linux_pci_find_irq_dev(irq); | ||||
if (dev == NULL) | if (dev == NULL) | ||||
return -EINVAL; | return -EINVAL; | ||||
irqe = linux_irq_ent(dev, irq); | irqe = lkpi_irq_ent(dev, irq); | ||||
if (irqe == NULL || irqe->tag != NULL) | if (irqe == NULL || irqe->tag != NULL) | ||||
return -EINVAL; | return -EINVAL; | ||||
return -bus_setup_intr(dev->bsddev, irqe->res, INTR_TYPE_NET | INTR_MPSAFE, | return -bus_setup_intr(dev->bsddev, irqe->res, INTR_TYPE_NET | INTR_MPSAFE, | ||||
NULL, linux_irq_handler, irqe, &irqe->tag); | NULL, linux_irq_handler, irqe, &irqe->tag); | ||||
} | } | ||||
static inline void | void | ||||
disable_irq(unsigned int irq) | lkpi_disable_irq(unsigned int irq) | ||||
{ | { | ||||
struct irq_ent *irqe; | struct irq_ent *irqe; | ||||
struct device *dev; | struct device *dev; | ||||
dev = linux_pci_find_irq_dev(irq); | dev = linux_pci_find_irq_dev(irq); | ||||
if (dev == NULL) | if (dev == NULL) | ||||
return; | return; | ||||
irqe = linux_irq_ent(dev, irq); | irqe = lkpi_irq_ent(dev, irq); | ||||
if (irqe == NULL) | if (irqe == NULL) | ||||
return; | return; | ||||
if (irqe->tag != NULL) | if (irqe->tag != NULL) | ||||
bus_teardown_intr(dev->bsddev, irqe->res, irqe->tag); | bus_teardown_intr(dev->bsddev, irqe->res, irqe->tag); | ||||
irqe->tag = NULL; | irqe->tag = NULL; | ||||
} | } | ||||
static inline int | int | ||||
bind_irq_to_cpu(unsigned int irq, int cpu_id) | lkpi_bind_irq_to_cpu(unsigned int irq, int cpu_id) | ||||
{ | { | ||||
struct irq_ent *irqe; | struct irq_ent *irqe; | ||||
struct device *dev; | struct device *dev; | ||||
dev = linux_pci_find_irq_dev(irq); | dev = linux_pci_find_irq_dev(irq); | ||||
if (dev == NULL) | if (dev == NULL) | ||||
return (-ENOENT); | return (-ENOENT); | ||||
irqe = linux_irq_ent(dev, irq); | irqe = lkpi_irq_ent(dev, irq); | ||||
if (irqe == NULL) | if (irqe == NULL) | ||||
return (-ENOENT); | return (-ENOENT); | ||||
return (-bus_bind_intr(dev->bsddev, irqe->res, cpu_id)); | return (-bus_bind_intr(dev->bsddev, irqe->res, cpu_id)); | ||||
} | } | ||||
static inline void | void | ||||
free_irq(unsigned int irq, void *device __unused) | lkpi_free_irq(unsigned int irq, void *device __unused) | ||||
{ | { | ||||
struct irq_ent *irqe; | struct irq_ent *irqe; | ||||
struct device *dev; | struct device *dev; | ||||
dev = linux_pci_find_irq_dev(irq); | dev = linux_pci_find_irq_dev(irq); | ||||
if (dev == NULL) | if (dev == NULL) | ||||
return; | return; | ||||
irqe = linux_irq_ent(dev, irq); | irqe = lkpi_irq_ent(dev, irq); | ||||
if (irqe == NULL) | if (irqe == NULL) | ||||
return; | return; | ||||
lkpi_irq_release(dev, irqe); | lkpi_irq_release(dev, irqe); | ||||
kfree(irqe); | kfree(irqe); | ||||
} | } | ||||
static inline void | void | ||||
devm_free_irq(struct device *xdev, unsigned int irq, void *p) | lkpi_devm_free_irq(struct device *xdev, unsigned int irq, void *p) | ||||
{ | { | ||||
struct device *dev; | struct device *dev; | ||||
struct irq_ent *irqe; | struct irq_ent *irqe; | ||||
dev = linux_pci_find_irq_dev(irq); | dev = linux_pci_find_irq_dev(irq); | ||||
if (dev == NULL) | if (dev == NULL) | ||||
return; | return; | ||||
if (xdev != dev) | if (xdev != dev) | ||||
return; | return; | ||||
irqe = linux_irq_ent(dev, irq); | irqe = lkpi_irq_ent(dev, irq); | ||||
if (irqe == NULL) | if (irqe == NULL) | ||||
return; | return; | ||||
lkpi_irq_release(dev, irqe); | lkpi_irq_release(dev, irqe); | ||||
lkpi_devres_unlink(dev, irqe); | lkpi_devres_unlink(dev, irqe); | ||||
lkpi_devres_free(irqe); | lkpi_devres_free(irqe); | ||||
return; | return; | ||||
} | } | ||||
static inline int | |||||
irq_set_affinity_hint(int vector, cpumask_t *mask) | |||||
{ | |||||
int error; | |||||
if (mask != NULL) | |||||
error = intr_setaffinity(vector, CPU_WHICH_IRQ, mask); | |||||
else | |||||
error = intr_setaffinity(vector, CPU_WHICH_IRQ, cpuset_root); | |||||
return (-error); | |||||
} | |||||
/* | |||||
* LinuxKPI tasklet support | |||||
*/ | |||||
typedef void tasklet_func_t(unsigned long); | |||||
struct tasklet_struct { | |||||
TAILQ_ENTRY(tasklet_struct) entry; | |||||
tasklet_func_t *func; | |||||
/* Our "state" implementation is different. Avoid same name as Linux. */ | |||||
volatile u_int tasklet_state; | |||||
atomic_t count; | |||||
unsigned long data; | |||||
}; | |||||
#define DECLARE_TASKLET(_name, _func, _data) \ | |||||
struct tasklet_struct _name = { .func = (_func), .data = (_data) } | |||||
#define tasklet_hi_schedule(t) tasklet_schedule(t) | |||||
extern void tasklet_schedule(struct tasklet_struct *); | |||||
extern void tasklet_kill(struct tasklet_struct *); | |||||
extern void tasklet_init(struct tasklet_struct *, tasklet_func_t *, | |||||
unsigned long data); | |||||
extern void tasklet_enable(struct tasklet_struct *); | |||||
extern void tasklet_disable(struct tasklet_struct *); | |||||
extern void tasklet_disable_nosync(struct tasklet_struct *); | |||||
extern int tasklet_trylock(struct tasklet_struct *); | |||||
extern void tasklet_unlock(struct tasklet_struct *); | |||||
extern void tasklet_unlock_wait(struct tasklet_struct *ts); | |||||
#endif /* _LINUX_INTERRUPT_H_ */ |