Migration Guide: QDMA to MDB5 DMA

arrow_back Software Docs

7. Code Migration Reference (continued)

Note

The code snippets shown below highlight the core functionality to illustrate the similarities and differences between QDMA and MDB5 DMA implementations.


7.2.5 Completion Handling

QDMA uses callback-based completion with async I/O support. MDB5 uses DMAEngine callback mechanism with dmaengine_result.

QDMA (driver/src/cdev.c) MDB5 DMA (client-driver/mdb5-dmaclient-cdev.c)
static int qdma_req_completed(
    struct qdma_request *req,
    unsigned int bytes_done, int err)
{
    struct qdma_io_cb *qiocb = container_of(
        req, struct qdma_io_cb, req);
    struct cdev_async_io *caio;
    ssize_t res, res2;

    caio = (struct cdev_async_io *)
        qiocb->private;

    unmap_user_buf(qiocb, req->write);
    iocb_release(qiocb);

    caio->res2 |= (err < 0) ? err : 0;
    if (caio->res2)
        caio->err_cnt++;
    caio->cmpl_count++;

    if (caio->cmpl_count == caio->req_count) {
        res = caio->cmpl_count - caio->err_cnt;
        res2 = caio->res2;
        caio->iocb->ki_complete(
            caio->iocb, res);
        kfree(caio->qiocb);
        kmem_cache_free(cdev_cache, caio);
    }
    return 0;
}
static void amd_mdb5_dma_comp_result_cb(
    void *args,
    const struct dmaengine_result *res)
{
    struct amd_mdb5_dma_aio_request *aio_req = NULL;
    struct amd_mdb5_dma_io_request *io_req = NULL;
    struct amd_mdb5_dma_channel *hchan = NULL;
    struct amd_mdb5_dma_io_completion *comp;

    comp = (struct amd_mdb5_dma_io_completion *)args;
    if (!comp || comp->comp_handled)
        return;

    if ((io_req = amd_mdb5_dma_comp2ioreq(comp))
            != NULL) {
        if ((comp->flags &
             (AMD_MDB5_DMA_CHAN_ASYNC_MODE |
              AMD_MDB5_DMA_CHAN_APERTURE_MODE)) &&
            (aio_req =
             amd_mdb5_dma_ioreq2aioreq(io_req))
                != NULL) {
            hchan = aio_req->hchan;
        } else {
            hchan = (struct amd_mdb5_dma_channel *)
                io_req->private;
        }
    }

    /* An abort occurred */
    if (res->result == DMA_TRANS_ABORTED) {
        amd_mdb5_dma_handle_abort(hchan,
            comp->flags &
                AMD_MDB5_DMA_CHAN_ASYNC_MODE,
            comp);
        return;
    }

    if (amd_mdb5_dma_comp_status_get(comp)
            == AMD_MDB5_DMA_REQ_ERROR)
        return;

    if (hchan)
        atomic64_inc(&hchan->stats.intr_rcvd);

    amd_mdb5_dma_comp_status_set(comp,
        AMD_MDB5_DMA_REQ_INTR_RECV);
    if (comp->kth &&
        (comp->flags &
         AMD_MDB5_DMA_CHAN_ASYNC_MODE))
        comp->kth->schedule = 1;

    if (comp->wq)
        wake_up_interruptible(comp->wq);
}

7.2.6 File Operations

Both expose character device interface. QDMA uses cdev with read/write/ioctl; MDB5 uses standard read/write with async I/O support.

QDMA (driver/src/cdev.c) MDB5 DMA (client-driver/mdb5-dmaclient-cdev.c)
static const struct file_operations
cdev_gen_fops = {
    .owner = THIS_MODULE,
    .open = cdev_gen_open,
    .release = cdev_gen_close,
    .write = cdev_gen_write,
    .write_iter = cdev_write_iter,
    .read = cdev_gen_read,
    .read_iter = cdev_read_iter,
    .unlocked_ioctl = cdev_gen_ioctl,
    .llseek = cdev_gen_llseek,
};
static struct file_operations
mdb5_dma_chan_fops = {
    .owner      = THIS_MODULE,
    .open       = mdb5_dma_ops_open,
    .release    = mdb5_dma_ops_release,
    .read       = mdb5_dma_ops_read,
    .write      = mdb5_dma_ops_write,
    .read_iter  = mdb5_dma_ops_read_aio,
    .write_iter = mdb5_dma_ops_write_aio,
    .llseek     = mdb5_dma_ops_llseek,
};

7.2.7 Control Ioctl Handler

QDMA uses netlink with genl_ops for control commands. MDB5 uses ioctl on /dev/mdb5_ctrl.

QDMA (driver/src/nl.c) MDB5 DMA (client-driver/mdb5-dmaclient-cdev.c)
static struct genl_ops xnl_ops[] = {
    {
        .cmd = XNL_CMD_DEV_LIST,
        .policy = xnl_policy,
        .doit = xnl_dev_list,
    },
    {
        .cmd = XNL_CMD_Q_ADD,
        .policy = xnl_policy,
        .doit = xnl_q_add,
    },
    {
        .cmd = XNL_CMD_Q_START,
        .policy = xnl_policy,
        .doit = xnl_q_start,
    },
    {
        .cmd = XNL_CMD_Q_STOP,
        .policy = xnl_policy,
        .doit = xnl_q_stop,
    },
    {
        .cmd = XNL_CMD_Q_DEL,
        .policy = xnl_policy,
        .doit = xnl_q_del,
    },
    // ...
};
static long mdb5_dma_cdev_ctrl_ioctl(
    struct file *filep,
    unsigned int cmd, unsigned long args)
{
    void __user *buf = (void __user *)args;
    struct amd_mdb5_dma_cdev_ctrl *ctrl;

    ctrl = filep->private_data;

    switch (cmd) {
    case AMD_MDB5_DMA_CTRL_CMD_MODE:
        copy_from_user(&cmode, buf, sz);
        mdb5_dma_ctrl_cmd_mode(ctrl,
            &cmode, true);
        break;
    case AMD_MDB5_DMA_CTRL_CMD_STATS:
        mdb5_dma_ctrl_cmd_stats(ctrl, &cstats);
        break;
    }
}

8. References

The following resources provide additional information: