Драйвер устройства Linux, обрабатывающий несколько источников / векторов прерываний - PullRequest
2 голосов
/ 21 марта 2011

Я пишу драйвер устройства для обработки прерываний для карты PCIe, которая в настоящее время работает для любого вектора прерывания, возникающего в линии IRQ.

Но у него есть несколько типов, которые можно вызвать, помеченные регистром вектора. Так что теперь мне нужно прочитать информацию о векторе и быть немного умнее ...
Итак, я: -

1 / иметь отдельные узлы dev /dev/int1, /dev/int2 и т. Д. Для каждого типа прерывания, и просто документ, который int1 предназначен для вектора типа A и т. Д.
1.1 / Поскольку каждый файл / char-device будет иметь свой собственный номер minor, при открытии я буду знать, что есть что. я думаю.
1.2 / ldd3, похоже, демонстрирует этот метод.

2 / Есть один узел /dev/int (как сейчас) и несколько процессов зависают от одного и того же метода read? звучит лучше?!
2.1 / Тогда только разбудить правильный процесс ...?
2.2 / Я использую отдельные wait_queue_head_t wait_queue с? Или разные flag / условия испытаний?

В методе read: -

    wait_event_interruptible(wait_queue, flag);

В обработчике не реальный код! : -

    int vector = read_vector();
    if vector = A then 
        wake_up_interruptible(wait_queue, flag)
        return IRQ_HANDLED;
    else
        return IRQ_NONE/IRQ_RETVAL?

РЕДАКТИРОВАТЬ: заметки от людей комментарии: -
1) мой код пользовательского пространства mmap всех регистров прошивки PCIe
2) Код пользовательского пространства имеет несколько потоков, каждый из которых выполняет блокировку read на узлах устройства драйвера устройства, которая затем возвращает данные из встроенного программного обеспечения при возникновении прерывания. Мне нужна правильная нить в зависимости от типа прерывания.

Ответы [ 3 ]

2 голосов
/ 22 марта 2011

Я не уверен, что правильно понимаю, что вы имеете в виду под регистром вектора (указатель на некоторую документацию поможет мне точно определить ваш случай).

В любом случае, любое PCI-устройство получает уникальный номер прерывания (заданный BIOS или некоторым программным обеспечением на других архитектурах, отличных от x86). Вам просто нужно зарегистрировать это прерывание в вашем драйвере.

priv->name = DRV_NAME;
err = request_irq(pdev->irq, your_irqhandler, IRQF_SHARED, priv->name,
          pdev);
if (err) {
    dev_err(&pdev->dev, "cannot request IRQ\n");
    goto err_out_unmap;
}

Еще одна вещь, которую я не совсем понимаю, это то, почему вы должны экспортировать свои прерывания как узел разработки: прерывания, безусловно, должны оставаться в коде вашего драйвера / ядра. Но я думаю, что здесь вы хотите экспортировать устройство, к которому затем осуществляется доступ в пользовательском пространстве. Я просто считаю / dev / int no хорошим названием.

По вашему вопросу о нескольких узлах разработки: если ваши разные источники прерываний предоставляют доступ к разным аппаратным ресурсам (даже если на одной плате PCI), я бы выбрал вариант 1) с ожиданием_квата для каждого устройства. Иначе я бы выбрал вариант 2)

Поскольку ваши прерывания исходят от одного и того же физического устройства, если вы выбрали вариант 1) или вариант 2), строка прерывания должна быть разделена, и вам придется читать вектор в вашем прерывании. обработчик, чтобы определить, какой аппаратный ресурс вызвал прерывание.

Для варианта 1) это будет примерно так:

static irqreturn_t pex_irqhandler(int irq, void *dev) {
    struct pci_dev *pdev = dev;
    int result;

    result = pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &myirq);

    if (result) {
         int vector = read_vector();
         if (vector == A) {
                set_flagA(flag);
         } else if (vector == B) {
                set_flagB(flag);
         }
         wake_up_interruptible(wait_queue, flag);
         return IRQ_HANDLED;
    } else {
         return IRQ_NONE;
}

Для варианта 2 он будет аналогичным, но у вас будет только одно условие if (для соответствующего векторного значения) в каждом отдельном обработчике прерываний, который вы будете запрашивать для каждого узла.

1 голос
/ 22 марта 2011

Во-первых, я предполагаю, что вы не пытаетесь вставить свой код в основное ядро. Если это так, ожидайте энергичного обсуждения наилучшего способа сделать это. Если вы пишете простой драйвер обработки прерываний для карты, которая в основном управляется mmap из пользовательского пространства, есть много способов решить эту проблему.

Если вы используете несколько узлов устройства (вариант 1), вы также можете реализовать poll, чтобы одно приложение могло открывать несколько узлов устройства и ожидать выбора прерываний. Младший номер будет достаточно, чтобы отличить их. Если у вас есть очередь для каждого вектора, вы можете разбудить только соответствующих слушателей. Вам нужно будет зафиксировать вектор после успешного poll, чтобы быть уверенным, что read завершится успешно.

Если вы используете один узел устройства (вариант 2), вам необходимо добавить дополнительную магию, чтобы потоки могли зарегистрировать свой интерес в определенных векторах прерываний. Вы можете сделать это с помощью ioctl или иметь потоки write векторов прерываний для устройства. Каждый поток должен открыть узел устройства, чтобы получить собственный дескриптор файла. Затем вы можете связать список запрашиваемых векторов с каждым дескриптором открытого файла. В качестве бонуса вы можете разрешить приложению read вектор прерывания от устройства, чтобы он знал, какой из них произошел.

Вам нужно подумать о том, как прерывание очищается. Обработчику прерываний потребуется удалить прерывание, а затем сохранить результат, чтобы его можно было передать в пространство пользователя. Для этого вам может пригодиться kfifo, а не очередь ожидания. Если у вас есть fifo для каждого дескриптора открытого файла, вы можете распространять уведомления о прерываниях для каждого прослушивающего приложения.

1 голос
/ 22 марта 2011

Если у вас есть другой канал, из которого вы можете read(), то вам определенно следует использовать другой младший номер. Представьте, что у вас есть карта с четырьмя последовательными портами, вам определенно понадобятся четыре /dev/ttySx.
Но подходит ли ваше устройство к этой модели?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...