Запуск транзакции DMA из обработчика irq в ядре Linux - PullRequest
0 голосов
/ 14 сентября 2018

Я разрабатываю драйвер для доски beaglebone черного цвета.Водитель общается с FPGA.Когда у fpga есть данные для чтения, запускается IRQ.Поэтому я должен быстро запустить транзакцию DMA для чтения данных.Можно ли запустить транзакцию из атомарного контекста?

На данный момент я отправляю задачу в высокоприоритетную рабочую очередь, и она запускает транзакцию DMA, но иногда, когда я работаю на скорости 30 Мбит / с, я получаю большое значение (около 200-500).микросекунды) между вызовом queue_work из обработчика irq и запуском задания из рабочей очереди.

Так можно ли запустить dma напрямую из irq или есть более быстрый способ запуска транзакции dma из обработчика irq?

Я использую ядро ​​Linux 4.9.

ОБНОВЛЕНО:

void init(){
    g_fpga_dma_queue = alloc_workqueue("fpga_dma_queue", WQ_UNBOUND |Q_HIGHPRI, 1);
}

static irq_handler_t irqReadyRead(unsigned int irq, void* dev_id, struct pt_regs* regs)
{
    if(g_fpga_dma_queue) {
        queue_work(g_fpga_dma_queue, &fpga_dma_work);
    }

    return (irq_handler_t)IRQ_HANDLED;
}

static void dma_callback_read(void *param)
{
    struct dma_chan *chan = g_dma_chan_read;

    switch (dma_async_is_tx_complete(chan, cookie_read, NULL, NULL)) {
        case DMA_COMPLETE:
            irqraised1_read = 1;
            g_good_dma++;
            break;

        case DMA_ERROR:
            irqraised1_read = -1;
            g_bad_dma++;
            break;

        default:
            irqraised1_read = -1;
            g_bad_dma++;
            break;
    }


    complete(&dma_comp_read);
}

static int read_dma(int count)
{
    struct dma_device *dev;
    struct dma_async_tx_descriptor *tx;
    unsigned long flags;
    int result = 0;

    dev = g_dma_chan_read->device;
    flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;

    tx = dev->device_prep_dma_memcpy(g_dma_chan_read, dmaphysbuf_read, (unsigned long) FPGA_READ_BUFFER_ADDR,
                                     (size_t) count, flags);

    if (!tx) {
        DBG_LOG("device_prep_dma_memcpy failed\n");

        return -ENODEV;
    }

    irqraised1_read = 0u;
    dma_comp_read.done = 0;

    /* set the callback and submit the transaction */
    tx->callback = dma_callback_read;
    tx->callback_param = NULL;
    cookie_read = dmaengine_submit(tx);
    dma_async_issue_pending(g_dma_chan_read);

    wait_for_completion(&dma_comp_read);

    /* Check the status of the completed transfer */

    if (irqraised1_read < 0) {
        DBG_LOG("edma copy: Event Miss Occured!!!\n");
        dmaengine_terminate_all(g_dma_chan_read);

        result = -EAGAIN;
    }
}
static void fpga_dma_work_handler(struct work_struct *w){
    size_t count = readSize();
    read_dma();
}

Иногда (когда мы вставляем или удаляем флешку, когда какой-либо драйвер пишет сообщения в терминале), я получаюочень большая задержка между обработчиком irq и началом работы dma (~ 1 мс)

1 Ответ

0 голосов
/ 17 сентября 2018

Я нашел основную причину задержек.Я получил огромную задержку в моем драйвере, когда какой-либо драйвер печатает что-то в консоли (когда я вставляю USB, удаляю сетевой кабель, вызываю printk из драйвера и т. Д.), Обычно у меня возникают максимальные задержки между запуском задачи в очереди работ и запуском транзакций dma около 100-200 микросекунд (~ 10-20 микросекунд для подготовки транзакции dma), и пока все в порядке.

И я нашел причину, по которой некоторые транзакции dma заканчиваются ошибками, когда я запускаю их непосредственно из обработчика irq, я получаю прерывания каждые ~ 500 микросекунд, и если задержка наступает после обработчика irq и до фактического запуска транзакции dma, я запускаю новыйтранзакция до завершения предыдущей (транзакция dma должна быть сделана очень быстро около 10 микросекунд, и я не проверяю, завершена ли предыдущая транзакция, и с однопоточным рабочим заданием было невозможно запустить следующую задачу до завершения предыдущей, поэтому я забыл проверить, завершена ли транзакциякогда я изменяю свой код для запуска транзакций из обработчика irq)

Теперь я продолжаю использовать очередь с высоким приоритетом с отключенным выводом ядра на консоль.И, может быть, я попытаюсь использовать рабочую очередь с заданием в тасклете, если мне понадобится меньшая задержка для запуска транзакции dma (я думаю, что запуск dma из irq не годится, потому что это занимает около 10-20 микросекунд в обработчике irq на моей плате, но, возможно, иногда это нормально)

...