Про очереди задач.

Выполнение функции в контексте прерывания должно происходить максимально быстро. Поэтому если требуется драйверу в момент прерывания выполнить какой-то большой объем работы, то имеет смысл поместить функцию в очередь задач (workqueue), для её отложенного выполнения. После помещения функции в очередь (schedule_work), она будет выполнена в ближайшее время в контексте ядра.

Пример модуля с вызовом отложенной функции. Структура создаётся статически на этапе компиляции.

/*
 *  stat_queue.c - статическая workqueue
 */
#include <linux/module.h>
#include <linux/workqueue.h>

#define DRIVER_AUTHOR "noname author "
#define DRIVER_DESC   "static queue"


/* функция, которую требуется вызвать в отложенном режиме */
static void my_function(struct work_struct *work){
  printk("call function from queue\n");
}

/* создание статической структуры на этапе компиляции
 * первый аргумент - имя для структуры struct work_struct, которая будет создана
 * второй аргумент - имя функции которую нужно отложенно выполнить */
static DECLARE_WORK(tst_queue_struct, my_function);

/* функция, которая вызывается при загрузке модуля */
static int __init init_stat_queue(void){
  printk(KERN_ALERT "Hello, static queue\n");

  /* помещение функции в очередь задач ядра */
  schedule_work(&tst_queue_struct);

  return 0;
}

static void __exit cleanup_stat_queue(void){
  printk(KERN_ALERT "Goodbye, static queue\n");
}

module_init(init_stat_queue);
module_exit(cleanup_stat_queue);

MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);

Makefile для сборки модуля:

obj-m += stat_queue.o

all:
                make -C /usr/src/linux-headers-`uname -r` M=$(PWD) modules

clean:
                rm -rf *.o *.ko

Структуру struct work_struct можно создавать динамически.

Пример отложенного выполнения функции (workqueue) с динамическим созданием структуры:

/*
 *  dynam_queue.c - динамически отложенное действие
 */
#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/slab.h>

#define DRIVER_AUTHOR "noname author "
#define DRIVER_DESC   "dynamic queue"

/* функция, которую требуется вызвать в отложенном режиме */
static void my_function(struct work_struct *work){
  printk("call function from queue\n");
}

/* функция, которая вызывается при загрузке модуля */
static int __init init_dynam_queue(void){
  printk(KERN_ALERT "Hello, dynamic queue\n");

  /* указатель на структуру work_struct */
  struct work_struct *tst_queue_struct;

  /* динамически выделяется область памяти под структуру */
  tst_queue_struct = kmalloc( sizeof(struct work_struct), GFP_KERNEL );

  /* динамически инициализируем структуру work_struct.
   * первый аргумент - имя для структуры struct work_struct для инициализации
   * второй аргумент - имя функции, которую нужно отложенно выполнить */
  INIT_WORK(tst_queue_struct, my_function);

  /* помещение функции в очередь задач ядра */
  schedule_work(tst_queue_struct);

  return 0;
}

static void __exit cleanup_dynam_queue(void){
  printk(KERN_ALERT "Goodbye, dynamic queue\n");
}

module_init(init_dynam_queue);
module_exit(cleanup_dynam_queue);

MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);

Если требуется передать какие-либо данные в отложенную функцию, то нужно создать свою структуру, где обязательным членом должно быть поле struct work_struct.
А затем уже в отложенной функции через макрос container_of получить доступ к
своим данным.

Пример использования отложенной функции (workqueue) с передачей параметров

/*  
 *  dynam_queue_2.c - динамически отложенное действие,
 *  с передачей параметров в отложенную функцию
 * 
 */
#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/slab.h>

#define DRIVER_AUTHOR "noname author "
#define DRIVER_DESC   "dynamic queue with param"

struct queue_data_struct {
  struct work_struct queue_work; /* необходимая структура */
  int    data;                   /* данные для передачи в функцию */
};

/* функция, которую требуется вызвать в отложенном режиме */
static void my_function(struct work_struct *work){
  printk("call function from queue\n");
  
  struct queue_data_struct *tst_queue_struct = container_of(work, 
      struct queue_data_struct, queue_work);  
  
  printk( "function param: data=%d\n", tst_queue_struct->data );
  kfree(tst_queue_struct);
}

/* функция, которая вызывается при загрузке модуля */
static int __init init_dynam_queue(void){
  printk(KERN_ALERT "Hello, dynamic queue\n");
  
  /* указатель на структуру work_struct */
  struct queue_data_struct *tst_queue_struct;

  /* динамически выделяется область памяти под структуру */
  tst_queue_struct = kmalloc( sizeof(struct queue_data_struct), GFP_KERNEL );

  /* динамически инициализируем структуру work_struct.
   * первый аргумент - имя для структуры struct work_struct для инициализации
   * второй аргумент - имя функции которую нужно отложенно выполнить */
  INIT_WORK(&(tst_queue_struct->queue_work), my_function);
  
  /* данные для передачи в отложенную функцию */
  tst_queue_struct->data = 99;

  /* помещение функции в очередь задач ядра */
  schedule_work(&(tst_queue_struct->queue_work));        
        
  return 0;
}

static void __exit cleanup_dynam_queue(void){
  printk(KERN_ALERT "Goodbye, dynamic queue\n");
}

module_init(init_dynam_queue);
module_exit(cleanup_dynam_queue);

MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);    
MODULE_DESCRIPTION(DRIVER_DESC);