ezdma icon indicating copy to clipboard operation
ezdma copied to clipboard

Use ezdma from kernel-space

Open ht-hieu opened this issue 7 years ago • 4 comments

Hi. I'm writing a DMA driver for my hardware. I don't know about parameter was set on FPGA. Your code works well in user-space. I tried you your code in my driver, but it cannot run get_user_pages_fast with my buffer. I also followed dmatest.c in xilinx's kernel, it work but when I transmit with higher speed, it showed error: xilinx-dma 40410000.dma: Channel ef31b890 has errors 11 cdr 0 cdr msb 0 tdr 0 tdr msb 0. Can you help me solve this error? Thank you. Here is my code:

static int dma_read(struct dma_priv *priv, uint8_t __kernel *buffer,
                      size_t count, uint32_t timeout)
{
        struct dma_device *device = priv->chan->device;
        struct dma_async_tx_descriptor *rxd = NULL;
        dma_addr_t dma_src;
        struct scatterlist rx_sg[1];
        struct completion rx_cmp;
        int i, ret=0;
        if (down_interruptible(&priv->sem)) {
                return -ERESTARTSYS;
        }

        dma_src = dma_map_page(device->dev, virt_to_page(buffer),
                               offset_in_page(buffer), count, DMA_DEV_TO_MEM);
        if (dma_mapping_error(device->dev, dma_src)) {
                error("Mapping error\n");
                ret = -1;
                goto read_map_err;
        }
        sg_init_table(rx_sg, 1);
        sg_dma_address(&rx_sg[0]) = dma_src;
        sg_dma_len(&rx_sg[0]) = count;
        rxd = dmaengine_prep_slave_single(priv->chan, dma_src, count,
                                          DMA_FROM_DEVICE, DMA_PREP_INTERRUPT);
        if (!rxd) {
                error(" prep err\n");
                dma_unmap_single(device->dev, dma_src, count, DMA_MEM_TO_DEV);
                ret = -1;
                goto read_out;
        }
        init_completion(&priv->completion);
        rxd->callback = dma_tx_callback;
        rxd->callback_param = priv;

        priv->cookie = dmaengine_submit(rxd);
        if (dma_submit_error(priv->cookie)) {
                warn("submit error\n");
        }
        dma_async_issue_pending(priv->chan);
        wait_for_completion(&priv->completion);

        if (dma_async_is_tx_complete(priv->chan, priv->cookie, NULL, NULL)
                != DMA_COMPLETE) {
                error("DMA error\n");
                ret = -1;
                goto read_out;
        }
        ret = priv->bytes_xfered;
read_map_err:
        dma_unmap_single(device->dev, dma_src, count, DMA_MEM_TO_DEV);
read_out:
        up(&priv->sem);
        return ret;
}

ht-hieu avatar Mar 01 '17 14:03 ht-hieu

@gochit,

ezdma is designed for use from userspace only, and get_user_pages_fast() is intended only for userspace (process virtual) memory, so I'm not surprised that it's not working when being called from within the kernel.

I think you're on the right track with your code above (calling the dmaengine API directly from within the kernel), but as far as debugging your specific issue I'd have to know more context. The meanings of register values printed in dmesg are explained in the AXI DMA Documentation (PG021).

jeremytrimble avatar Mar 30 '17 16:03 jeremytrimble

@jeremytrimble ,

Thank you for your response, according to AXI DMA Documentation, DMA driver turned on 2 bits:

DMA channel halted. For Scatter / Gather Mode this bit gets set when DMACR.RS = 0 and DMA and 
scatter Gather (SG) operations have halted. For Direct Register mode (C_INCLUDE_SG = 0) this bit gets 
set when DMACR.RS = 0 and DMA operations have halted. There can be a lag of time between when 
DMACR.RS = 0 and when DMASR.Halted = 1
DMA Internal Error. Internal error occurs if the buffer length specified in the fetched descriptor
is set to 0. This error condition causes the AXI DMA to halt gracefully. The DMACR.RS bit is set 
to 0, and when the engine has completely shut down, the DMASR.Halted bit is set to 1.

I don't know why channel turned off and this error only occurs when I increase the speed to larger than thread hold (2Mbit/s). My code is very simple, it receives bytes from DMA and sends to another module in an infinity loop.

ht-hieu avatar Mar 31 '17 07:03 ht-hieu

@gochit: You mentioned that you didn't know how the core's parameters were set when your FPGA image was built -- perhaps as you increase the size of your transfers you are exceeding the configured length of the transfer size register. When the upper bits of your transfer size are lost, the truncated result might be all zeros, which would cause the error you see.

In some versions of the xilinx AXI DMA driver, you can set the register length as a device tree parameter. Even if you don't know exactly how the AXI DMA's register length was configured in your FPGA image, you could always set the value in the device tree to something lower and it should still work, at the expense of using more descriptors than necessary.

jeremytrimble avatar Apr 04 '17 16:04 jeremytrimble

@jeremytrimble

I still don't know why this error occurs. When I can reduce the frequency of errors by increase buffer size which is mapped to DMA. When I increased writing speed, your driver got the same error. BTW, I replaced DMA single with DMA coherent and the performance is much better, now I can ignore this error 😀

ht-hieu avatar Apr 18 '17 03:04 ht-hieu