Обработка прерывания в символьном устройстве

Я пытаюсь правильно зарегистрировать прерывание в ядре для пользовательского интерфейса.

Удивительно, но я не нашел много примеров в ядре для этого.

обработчик прерываний

static irqreturn_t irq_handler(int irq, void *dev_id)
{
   struct el_irq_dev *el_irq = &el_irq_devices[0];
    printk("irq in\n");

    spin_lock(&el->my_lock,flags);

    clear_interrupt() 

    some_buffer[buf_wr] = ch;
    el_irq->buf_wr++;
    if (el_irqbuf_wr >= 16)
        el_irqbuf_wr = 0;


     spin_unlock(&el->my_lock,flags);
     wake_up_interruptible(&el->pollw);



return IRQ_HANDLED;

}

ioctl для ожидания прерываний

static long el_device_ioctl( struct file *filp, 
         unsigned int ioctl_num, 
         unsigned long ioctl_param)
{
    struct el_irq_dev *el_irq = &el_irq_devices[0];
switch (ioctl_num) {
case IOCTL_WAIT_IRQ:      <<<---- using ioctl (no poll) to wait on interrupt
    wait_event_interruptible(el_irq->pollw, &el_irq->buf_wr != &el_irq->buf_rd) ;
    spin_lock(&el_irq->my_lock);
    if (el_irq->buf_wr != &el_irq->buf_rd)
    {
        my_value=some_buffer[el_irq->buf_rd];
        el_irq->buf_rd++;
        if (el_irq->buf_rd >= 16)
            el_irq->buf_rd = 0;
    }

    spin_unlock(&el_irq->my_lock);
    copy_to_user(ioctl_param,&my_value,sizeof(my_value));

default:
        break;
    }
    return 0;
}

Мой вопрос:

  1. Должны ли мы поставить очистку от прерываний (clear_interrupt()) в fpga в прерывании до или после wake_up? Можем ли мы поместить прерывание очистки в обработчик пользовательского пространства (IOCTL_WAIT_IRQ) ​​вместо очистки прерывания в обработчике прерываний?
  2. Как видно из кода, я использую циклический буфер для обработки случаев, когда в обработчике пользовательского пространства отсутствуют прерывания. Это действительно необходимо или можно считать, что промахов нет? Другими словами, разумно ли предположить, что прерывания никогда не должны быть пропущены? так что вызов ioctl никогда не должен видеть более 1 ожидающего прерывания? Если да - возможно, мне не нужен буферный механизм между обработчиком прерывания и обработчиком ioctl.

Спасибо, Ран


person ransh    schedule 20.01.2017    source источник
comment
Зачем вам все это в первую очередь?   -  person 0andriy    schedule 20.01.2017
comment
У нас есть пространство памяти fpga, и вместо этого мы делаем большинство драйверов в пользовательском пространстве и просто сигнализируем прерывание пользовательскому пространству из ядра.   -  person ransh    schedule 20.01.2017
comment
Какая память? Общее назначение? Почему бы не использовать для этого DMA в драйвере ядра?   -  person 0andriy    schedule 20.01.2017


Ответы (1)


Короткий ответ.

  1. Мне кажется разумным очищать прерывания в обработчике пользовательского пространства. Имеет смысл сделать это как можно позже, после того, как вся работа была сделана, при условии, что вы снова проверяете после очистки, что на самом деле не осталось работы (еще какая-то работа могла быть получена непосредственно перед очисткой).
  2. Обработчик пользовательского пространства действительно может пропустить прерывания, например. если несколько приходят между вызовами IOCTL_WAIT_IRQ. Прерывания также могут быть в некотором смысле «пропущены», если несколько частей работы поступают до того, как прерывания будут очищены. Стек (аппаратное и программное обеспечение) должен быть спроектирован таким образом, чтобы это не было проблемой. Прерывание должно просто сигнализировать о том, что есть работа, которую нужно выполнить, и обработчик пользовательского пространства должен иметь возможность просто выполнить всю оставшуюся работу перед возвратом.
  3. Вероятно, вам следует использовать spin_lock_irqsave() в коде IOCtl[1].

[1] http://www.makelinux.net/ldd3/chp-5-sect-5

person michaeljt    schedule 20.01.2017
comment
Спасибо за подробный ответ. Разумно ли предположить, что никогда не должно быть пропущенных прерываний? то есть ioctl никогда не должен видеть более 1 ожидающего прерывания? Если да - возможно мне не нужен буферный механизм между обработчиком прерывания и ioctl - person ransh; 20.01.2017
comment
Не совсем уверен, что вы имеете в виду под пропущенными прерываниями здесь. Самое простое — заставить обработчик IOCtl (не беспокойтесь о моих столицах, есть несколько вариантов) возвращаться, как только было хотя бы одно прерывание с момента последнего clear_interrupts(). Но обработчик пользовательского пространства должен предполагать, что могло быть несколько прерываний с момента последнего возврата IOCtl, и у обработчика пользовательского пространства должен быть способ узнать обо всей работе, о которой сообщали эти прерывания. - person michaeljt; 20.01.2017
comment
поэтому я предполагаю, что механизм буфера, который я использовал в этом примере (some_buffer), весьма важен. - person ransh; 20.01.2017
comment
Если это единственный способ предоставить пользовательскому пространству всю работу, то да. В вашем коде вы назначаете ch текущему слоту буфера, но я не вижу, откуда вы берете ch или что это такое (полагаю, вы просто исключили его из кода скетча). Многие аппаратные средства будут реализовывать внутренний буфер, такой как some_buffer, чтобы конечный обработчик (в данном случае в пользовательском пространстве) мог читать напрямую. В этом случае some_buffer не понадобится. Если это оборудование не делает этого, вам действительно следует убедиться, что вы очищаете прерывания как можно быстрее, чтобы не пропустить работу. Это помогло? - person michaeljt; 20.01.2017
comment
да, очень помогло! Я также отметил это как решение. Я тоже теперь начинаю думать, что мне действительно не нужен этот буфер, потому что об этом заботится HW. пока я не очищаю прерывание в fpga, я ожидаю, что буфер fpga не будет заполняться больше, чем ожидалось. Так что, вероятно, не должно быть никаких реальных проблем - если - обработчик пользовательского пространства (который ожидает ioctl) достаточно быстр, чтобы скопировать буфер и очистить прерывание, верно? - person ransh; 20.01.2017
comment
Я ожидаю, что внутренний буфер FPGA будет заполняться с той же скоростью, независимо от того, очищаете ли вы прерывания. Если ваш код обработки прерываний, будь то ядро ​​или пользовательское пространство, не может считывать данные быстрее, чем они приходят, вероятно, произойдет переполнение буфера (не тип языка C) и данные будут потеряны. Это просто происходит, когда данные поступают быстрее, чем вы можете с ними справиться. Но если вы читаете его посимвольно, то я предполагаю, что он не приходит так быстро. Я также предполагаю, что данные останутся в буфере FPGA, пока ваш обработчик не прочитает их, независимо от того, сколько прерываний произошло. - person michaeljt; 20.01.2017