Обработчик IRQ не регистрируется

Я изучаю обработку прерываний в ядре Linux и попытался ниже фрагмент кода зарегистрировать фиктивный обработчик IRQ на IRQ2. Но, похоже, он не регистрируется, так как я вижу отрицательное возвращаемое значение и сообщение в ядре, как показано ниже, возникающее из функции очистки, которая пытается выполнить free_irq():

[ 2203.989585] Trying to free already-free IRQ 2

ниже приведен printk из журнала ядра, который предполагает, что он не зарегистрирован:

Here with registering IRQ handler on IRQ2 for flowTest...retval_irqreg= -22

Ниже приведена соответствующая часть моего кода, которая имеет четыре функции.

1 the bottom half 
2. handler 
3. init function 
4. cleanup function

Я еще не планирую нижнюю половину, хотя она присутствует ниже. Я работаю над ядром 3.5.0-17.

//Bottom half for the irq handler
static void bh_flowTest()
    {
        printk(KERN_INFO "Inside bottom half for flowTest.\n");
    }
// IRQ handler function
static irqreturn_t flow_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
                {
                printk(KERN_INFO "This is flowTest IRQ handler.\n");

        //static struct tq_struct task = {NULL, 0, bh_flowTest, NULL};
                /* Schedule bottom half to run */
        //queue_task(&task, &tq_immediate);

        // mark_bh(IMMEDIATE_BH);
    return IRQ_HANDLED;             
        }

static int flow_init(void)
    {
    printk(KERN_ALERT "Here with flowTest module ... loading...\n");
 int result=0;
 dev_t dev=0;
result = alloc_chrdev_region(&dev, minor_num,
num_devices,"mod_flowtest");                              // allocate major number dynamically.

i=MAJOR(dev);
printk(KERN_ALERT "Major allocated = %d",i);

cdev_init(&ms_flow_cd,&flow_fops);
cdev_add(&ms_flow_cd,dev,1);

//Registering interrupt handler on IRQ2 since IRQ2 is free as per /proc/interrupts
int retval_irqreg;
retval_irqreg=request_irq(2,(irq_handler_t)flow_irq_handler, /* our handler. It has been typecasted to remove warnings of incompatible pointer type , and enum irqreturn_t. Try removing the cast and see the warnings */
              IRQF_SHARED, 
              "test_flow_irq_handler", NULL);
printk(KERN_ALERT "Here with registering IRQ handler on IRQ2 for flowTest...retval_irqreg= %d\n",retval_irqreg);

return 0;
    }

static void flow_terminate(void)
    {
    dev_t devno=MKDEV(i,0);         // wrap major/minor numbers in a dev_t structure , to pass for deassigning.
    printk(KERN_ALERT "Going out... exiting...\n");
    unregister_chrdev_region(devno,num_devices);        //remove entry from the /proc/devices

    free_irq(2, NULL);
    }

Я чувствую, что есть какая-то основная ошибка, но если кто-то может указать мне на это, пожалуйста..!


person Diwakar Sharma    schedule 09.08.2013    source источник
comment
На каком оборудовании вы пытаетесь это сделать? Является ли 2 действительным номером IRQ на нем?...   -  person TheCodeArtist    schedule 09.08.2013
comment
В данный момент я не делаю ничего конкретного для аппаратного обеспечения (устройства). Просто пытаюсь увидеть регистрацию обработчика. Что касается аппаратного обеспечения платформы, над которой я работаю, это 32-разрядная версия x86, похоже, у нее есть IRQ2, потому что приведенное ниже сообщение предполагает, что я пытаюсь освободить уже свободный IRQ 2. Надеюсь, я понимаю и не делаю глупостей.   -  person Diwakar Sharma    schedule 09.08.2013
comment
Сообщение Trying to free already-free IRQ 2 означает, что текущий драйвер не зарегистрировал обработчик прерывания для прерывания с номером 2. Это НЕ означает, что такое действительное IRQ существует.   -  person TheCodeArtist    schedule 09.08.2013


Ответы (1)


Похоже, что IRQ 2 еще НЕ существует на вашем оборудовании. т. е. когда вы вызываете request_irq(), ядро ​​Linux еще НЕ знает, какое прерывание на какой физической линии с какого периферийного оборудования должно рассматриваться как триггер для номера IRQ 2, поскольку это просто номер, который еще НЕ связан с любым фактическим физическим прерыванием).

По сути, сначала нужно связать конкретный номер IRQ с реальным физическим аппаратным прерыванием, прежде чем пытаться зарегистрировать ISR для этого номера IRQ. это обычно делается в ядре Linux с использованием < сильный>irq_domain_add_linear().

В прошлом номера IRQ можно было выбирать таким образом, чтобы они соответствовали линии аппаратного IRQ в корневом контроллере прерываний (то есть компоненте, фактически запускающем линию прерывания на ЦП), в настоящее время этот номер является просто числом.

API irq_alloc_desc*() и irq_free_desc*() обеспечивают выделение номеров IRQ, но не поддерживают обратное сопоставление номера IRQ локального контроллера (hwirq) с номером IRQ Linux. числовое пространство.

Текущий дизайн ядра Linux использует единое пространство больших чисел, где каждому отдельному источнику IRQ назначается отдельный номер. Это просто, когда имеется только один контроллер прерываний, но в системах с несколькими контроллерами прерываний ядро ​​должно гарантировать, что каждому из них назначено неперекрывающееся распределение номеров IRQ Linux.

Более подробная информация содержится в Documentation/IRQ-domain.txt< /а>.

Также вас может заинтересовать регистрация ISR для существующего прерывания (скажем, IRQ клавиатуры?). Когда для одного IRQ зарегистрировано несколько ISR, ядро ​​Linux будет вызывать каждый из ISR в каждом драйвере, который зарегистрировать общий irq.

person TheCodeArtist    schedule 09.08.2013
comment
значит ли это, что обработчик IRQ не может быть зарегистрирован на номере IRQ, пока у нас не будет фактического оборудования/устройства, выделенного для этой линии IRQ? - person Diwakar Sharma; 09.08.2013
comment
да. При вызове request_irq() сначала пытается выяснить desc которому принадлежит номер прерывания. Если он не найдет его, он вернет EINVAL (-22), что вы и получаете в качестве возвращаемого значения request_irq(). - person TheCodeArtist; 10.08.2013