Thread (4 messages) read the whole thread 4 messages, 2 authors, 2021-07-05

Re: [PATCH V4 RESEND] dmaengine: Loongson1: Add Loongson1 dmaengine driver

From: Kelvin Cheung <keguang.zhang@gmail.com>
Date: 2021-07-04 14:45:45
Also in: linux-mips, lkml

Vinod Koul [off-list ref] 于2021年6月7日周一 下午7:07写道:
On 21-05-21, 07:02, Keguang Zhang wrote:
quoted
+config LOONGSON1_DMA
+     tristate "Loongson1 DMA support"
+     depends on MACH_LOONGSON32
Why does it have to do that? The dma driver is generic..
This driver is only available for LOONGSON32 CPUs.
quoted
+static int ls1x_dma_alloc_chan_resources(struct dma_chan *dchan)
+{
+     struct ls1x_dma_chan *chan = to_ls1x_dma_chan(dchan);
+
+     chan->desc_pool = dma_pool_create(dma_chan_name(dchan),
+                                       dchan->device->dev,
+                                       sizeof(struct ls1x_dma_lli),
+                                       __alignof__(struct ls1x_dma_lli), 0);
+     if (!chan->desc_pool) {
+             dev_err(chan2dev(dchan),
+                     "failed to alloc DMA descriptor pool!\n");
This can be dropped, allocators will warn you for the allocation
failures
will do.
quoted
+             return -ENOMEM;
+     }
+
+     return 0;
+}
+
+static void ls1x_dma_free_desc(struct virt_dma_desc *vdesc)
+{
+     struct ls1x_dma_desc *desc = to_ls1x_dma_desc(vdesc);
+
+     if (desc->nr_descs) {
+             unsigned int i = desc->nr_descs;
+             struct ls1x_dma_hwdesc *hwdesc;
+
+             do {
+                     hwdesc = &desc->hwdesc[--i];
+                     dma_pool_free(desc->chan->desc_pool, hwdesc->lli,
+                                   hwdesc->phys);
+             } while (i);
+     }
+
+     kfree(desc);
+}
+
+static struct ls1x_dma_desc *ls1x_dma_alloc_desc(struct ls1x_dma_chan *chan,
+                                              int sg_len)
single line now :)
will do.
quoted
+{
+     struct ls1x_dma_desc *desc;
+     struct dma_chan *dchan = &chan->vchan.chan;
+
+     desc = kzalloc(struct_size(desc, hwdesc, sg_len), GFP_NOWAIT);
+     if (!desc)
+             dev_err(chan2dev(dchan), "failed to alloc DMA descriptor!\n");
this can be dropped too..
will do.
quoted
+static struct dma_async_tx_descriptor *
+ls1x_dma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
+                    unsigned int sg_len,
+                    enum dma_transfer_direction direction,
+                    unsigned long flags, void *context)
+{
+     struct ls1x_dma_chan *chan = to_ls1x_dma_chan(dchan);
+     struct dma_slave_config *cfg = &chan->cfg;
+     struct ls1x_dma_desc *desc;
+     struct scatterlist *sg;
+     unsigned int dev_addr, bus_width, cmd, i;
+
+     if (!is_slave_direction(direction)) {
+             dev_err(chan2dev(dchan), "invalid DMA direction!\n");
+             return NULL;
+     }
+
+     dev_dbg(chan2dev(dchan), "sg_len=%d, dir=%s, flags=0x%lx\n", sg_len,
+             direction == DMA_MEM_TO_DEV ? "to device" : "from device",
+             flags);
+
+     switch (direction) {
+     case DMA_MEM_TO_DEV:
+             dev_addr = cfg->dst_addr;
+             bus_width = cfg->dst_addr_width;
+             cmd = LS1X_DMA_RAM2DEV | LS1X_DMA_INT;
+             break;
+     case DMA_DEV_TO_MEM:
+             dev_addr = cfg->src_addr;
+             bus_width = cfg->src_addr_width;
+             cmd = LS1X_DMA_INT;
+             break;
+     default:
+             dev_err(chan2dev(dchan),
+                     "unsupported DMA transfer mode! %d\n", direction);
+             return NULL;
will this be ever executed?
just in case.
quoted
+static int ls1x_dma_slave_config(struct dma_chan *dchan,
+                              struct dma_slave_config *config)
+{
+     struct ls1x_dma_chan *chan = to_ls1x_dma_chan(dchan);
+
+     if (!dchan)
+             return -EINVAL;
should this not be checked before you dereference this to get chan
will drop this check.
quoted
+static void ls1x_dma_trigger(struct ls1x_dma_chan *chan)
+{
+     struct dma_chan *dchan = &chan->vchan.chan;
+     struct ls1x_dma_desc *desc;
+     struct virt_dma_desc *vdesc;
+     unsigned int val;
+
+     vdesc = vchan_next_desc(&chan->vchan);
+     if (!vdesc) {
+             dev_warn(chan2dev(dchan), "No pending descriptor\n");
Hmm, I would not log that... this is called from
ls1x_dma_issue_pending() and which can be called from client driver but
previous completion would push and this can find empty queue so it can
happen quite frequently
will drop this warning.
quoted
+static irqreturn_t ls1x_dma_irq_handler(int irq, void *data)
+{
+     struct ls1x_dma_chan *chan = data;
+     struct dma_chan *dchan = &chan->vchan.chan;
+
+     dev_dbg(chan2dev(dchan), "DMA IRQ %d on channel %d\n", irq, chan->id);
+     if (!chan->desc) {
+             dev_warn(chan2dev(dchan),
+                      "DMA IRQ with no active descriptor on channel %d\n",
+                      chan->id);
single line pls
will do.
quoted
+             return IRQ_NONE;
+     }
+
+     spin_lock(&chan->vchan.lock);
+
+     if (chan->desc->type == DMA_CYCLIC) {
+             vchan_cyclic_callback(&chan->desc->vdesc);
+     } else {
+             list_del(&chan->desc->vdesc.node);
+             vchan_cookie_complete(&chan->desc->vdesc);
+             chan->desc = NULL;
+     }
not submitting next txn, defeats the purpose of dma if we dont push txns
as fast as possible..
will fix it.
quoted
+static struct platform_driver ls1x_dma_driver = {
+     .probe  = ls1x_dma_probe,
+     .remove = ls1x_dma_remove,
+     .driver = {
+             .name   = "ls1x-dma",
+     },
No device tree?
Because the LOONGSON32 platform doesn't support DT yet.
--
~Vinod


-- 
Best regards,

Kelvin Cheung
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help