Index: sys/compat/linuxkpi/common/include/linux/irq_work.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/irq_work.h +++ sys/compat/linuxkpi/common/include/linux/irq_work.h @@ -31,22 +31,32 @@ #ifndef __LINUX_IRQ_WORK_H__ #define __LINUX_IRQ_WORK_H__ -#include +#include +#include + +struct irq_work; +typedef void (*irq_work_func_t)(struct irq_work *); struct irq_work { - struct work_struct work; + struct task irq_task; + irq_work_func_t func; }; -static inline void -init_irq_work(struct irq_work *irqw, void (*func)(struct irq_work *)) -{ - INIT_WORK(&irqw->work, (work_func_t)func); +#define DEFINE_IRQ_WORK(name, _func) struct irq_work name = { \ + .irq_task = TASK_INITIALIZER(0, linux_irq_work_fn, &(name)), \ + .func = (_func), \ } +void linux_irq_work_fn(void *, int); + static inline void -irq_work_queue(struct irq_work *irqw) +init_irq_work(struct irq_work *irqw, irq_work_func_t func) { - schedule_work(&irqw->work); + TASK_INIT(&irqw->irq_task, 0, linux_irq_work_fn, irqw); + irqw->func = func; } +#define irq_work_queue(irqw) linux_irq_work_queue(irqw) +void linux_irq_work_queue(struct irq_work *); + #endif /* __LINUX_IRQ_WORK_H__ */ Index: sys/compat/linuxkpi/common/src/linux_work.c =================================================================== --- sys/compat/linuxkpi/common/src/linux_work.c +++ sys/compat/linuxkpi/common/src/linux_work.c @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -59,6 +60,8 @@ struct workqueue_struct *system_highpri_wq; struct workqueue_struct *system_power_efficient_wq; +static struct taskqueue *linux_irq_work_tq; + static int linux_default_wq_cpus = 4; static void linux_delayed_work_timer_fn(void *); @@ -683,3 +686,37 @@ system_highpri_wq = NULL; } SYSUNINIT(linux_work_uninit, SI_SUB_TASKQ, SI_ORDER_THIRD, linux_work_uninit, NULL); + +void +linux_irq_work_fn(void *context, int pending) +{ + struct irq_work *irqw = context; + + irqw->func(irqw); +} + +void +linux_irq_work_queue(struct irq_work *irqw) +{ + taskqueue_enqueue(linux_irq_work_tq, &irqw->irq_task); +} + +static void +linux_irq_work_init(void *arg) +{ + linux_irq_work_tq = taskqueue_create_fast("linuxkpi_irq_wq", + M_WAITOK, taskqueue_thread_enqueue, &linux_irq_work_tq); + taskqueue_start_threads(&linux_irq_work_tq, 1, PWAIT, + "linuxkpi_irq_wq"); +} +SYSINIT(linux_irq_work_init, SI_SUB_TASKQ, SI_ORDER_SECOND, + linux_irq_work_init, NULL); + +static void +linux_irq_work_uninit(void *arg) +{ + taskqueue_drain_all(linux_irq_work_tq); + taskqueue_free(linux_irq_work_tq); +} +SYSUNINIT(linux_irq_work_uninit, SI_SUB_TASKQ, SI_ORDER_SECOND, + linux_irq_work_uninit, NULL);