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: