Библиотека сайта rus-linux.net
Цилюрик О.И. Модули ядра Linux | ||
Назад | Внутренние механизмы ядра | Вперед |
Управление линиями прерывания
Под управлением линиями прерываний, в этом месте описаний, мы будем понимать запрет-разрешение прерываний поодной или нескольким линиям irq. Раньше существовала возможность вообще запретить прерывания (на время, естественно). Но сейчас («заточенный» под SMP) набор API для этих целей выглядит так: либо вы запрещаете прерывания по всем линиям irq, но локального процессора, либо на всех процессорах, но только для одной линии irq.
Макросы управления линиями прерываний определены в <linux/irqflags.h>. Управление запретом и разрешением прерываний на локальном процессоре:
local_irq_disable() - запретить прерывания на локальном CPU;
local_irq_enable() - разрешить прерывания на локальном CPU;
int irqs_disabled() - возвратить ненулевое значение, если запрещены прерывания на локальном CPU, в противном случае возвращается нуль ;
Напротив, управление (запрет и разрешение) одной выбранной линией irq, но уже относительно всех процессоров в системе, делают макросы:
void disable_irq( unsigned int irq ) -
void disable_irq_nosync( unsigned int irq ) - обе эти функции запрещают прерывания с линии irq на контроллере (для всех CPU), причём, disable_irq() не возвращается до тех пор, пока все обработчики прерываний, которые в данный момент выполняются, не закончат работу;
void enable_irq( unsigned int irq ) - разрешаются прерывания с линии irq на контроллере (для всех CPU);
void synchronize_irq( unsigned int irq ) - ожидает пока завершится обработчик прерывания от линии irq (если он выполняется), в принципе, хорошая идея — всегда вызывать эту функцию перед выгрузкой модуля использующего эту линию IRQ;
Вызовы функций disable_irq*() и enable_irq() должны обязательно быть парными - каждому вызову функции запрещения линии должен соответствовать вызов функции разрешения. Только после последнего вызова функции enable_irq() линия запроса на прерывание будет снова разрешена.
Пример обработчика прерываний
Обычно затруднительно показать работающий код обработчика прерываний, потому что такой код должен был бы быть связан с реальным аппаратным расширением, и таким образом он будет перегружен специфическими деталями, скрывающими суть происходящего. Но оригинальный пример приведен в [6], откуда мы его и заимствуем (архив IRQ.tgz):
lab1_interrupt.c :
#include <linux/module.h> #include <linux/init.h> #include <linux/interrupt.h> #define SHARED_IRQ 17 static int irq = SHARED_IRQ, my_dev_id, irq_counter = 0; module_param( irq, int, S_IRUGO ); static irqreturn_t my_interrupt( int irq, void *dev_id ) { irq_counter++; printk( KERN_INFO "In the ISR: counter = %d\n", irq_counter ); return IRQ_NONE; /* we return IRQ_NONE because we are just observing */ } static int __init my_init( void ) { if ( request_irq( irq, my_interrupt, IRQF_SHARED, "my_interrupt", &my_dev_id ) ) return -1; printk( KERN_INFO "Successfully loading ISR handler on IRQ %d\n", irq ); return 0; } static void __exit my_exit( void ) { synchronize_irq( irq ); free_irq( irq, &my_dev_id ); printk( KERN_INFO "Successfully unloading, irq_counter = %d\n", irq_counter ); } module_init( my_init ); module_exit( my_exit ); MODULE_AUTHOR( "Jerry Cooperstein" ); MODULE_DESCRIPTION( "LDD:1.0 s_08/lab1_interrupt.c" ); MODULE_LICENSE( "GPL v2" );
Логика этого примера в том, что обработчик вешается в цепочку с существующим в системе, но он не нарушает работу ранее работающего обработчика, фактически ничего не выполняет, но подсчитывает число обработанных прерываний. В оригинале предлагается опробовать его с установкой на IRQ сетевой платы, но ещё показательнее — с установкой на IRQ клавиатуры (IRQ 1) или мыши (IRQ 12) на интерфейсе PS/2 (если таковой используется в компьютере):
$ cat /proc/interrupts
CPU0 0: 20329441 XT-PIC timer 1: 423 XT-PIC i8042 ...
$ sudo /sbin/insmod lab1_interrupt.ko irq=1
$ cat /proc/interrupts
CPU0 0: 20527017 XT-PIC timer 1: 572 XT-PIC i8042, my_interrupt ...
$ sudo /sbin/rmmod lab1_interrupt
$ dmesg | tail -n5 In the ISR: counter = 33 In the ISR: counter = 34 In the ISR: counter = 35 In the ISR: counter = 36 Successfully unloading, irq_counter = 36
$ cat /proc/interrupts
CPU0 0: 20568216 XT-PIC timer 1: 622 XT-PIC i8042 ...
Оригинальность такого подхода в том, что на подобном коде можно начать отрабатывать код модуля реального устройства, ещё не имея самого устройства, и имитируя его прерывания одним из штатных источников прерываний компьютера, с тем, чтобы позже всё это переключить на реальную линию IRQ, используемую устройством.
Предыдущий раздел: | Оглавление | Следующий раздел: |
Обработчик прерываний, верхняя половина | Отложенная обработка, нижняя половина |