Re: [PATCH v2 3/4] dma: Add Actions Semi Owl family S900 DMA driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Vinod,

On Tue, Jul 24, 2018 at 06:39:43PM +0530, Vinod wrote:
> somehow this got stuck so sending again...
> 
> On 24-07-18, 18:16, Vinod wrote:
> > On 23-07-18, 09:47, Manivannan Sadhasivam wrote:
> > 
> > > +#include <linux/bitops.h>
> > > +#include <linux/clk.h>
> > > +#include <linux/delay.h>
> > > +#include <linux/dmaengine.h>
> > > +#include <linux/dma-mapping.h>
> > > +#include <linux/dmapool.h>
> > > +#include <linux/err.h>
> > > +#include <linux/init.h>
> > > +#include <linux/interrupt.h>
> > > +#include <linux/io.h>
> > > +#include <linux/mm.h>
> > > +#include <linux/module.h>
> > > +#include <linux/of_device.h>
> > > +#include <linux/of_dma.h>
> > 
> > do you need this?
> > 

Not now ;-) will remove this.

> > > +/* OWL_DMAX_MODE Bits */
> > > +#define OWL_DMA_MODE_TS(x)			(((x) & 0x3f) << 0)
> > > +#define OWL_DMA_MODE_ST(x)			(((x) & 0x3) << 8)
> > > +#define	OWL_DMA_MODE_ST_DEV			OWL_DMA_MODE_ST(0)
> > > +#define	OWL_DMA_MODE_ST_DCU			OWL_DMA_MODE_ST(2)
> > > +#define	OWL_DMA_MODE_ST_SRAM			OWL_DMA_MODE_ST(3)
> > 
> > what are you trying to do with this? Generally we would define register
> > bits using BIT and GENMASK here..
> > 

Okay. Not sure about BIT() but I can use GENMASK() here.

> > > +/* Extract the bit field to new shift */
> > > +#define BIT_FIELD(val, width, shift, newshift)	\
> > > +		((((val) >> (shift)) & ((BIT(width)) - 1)) << (newshift))
> > 
> > why new shift? I guess you want to extract bits from a register here and
> > use those, right?
> > 

No. Here we are trying to pack two bit fields in a single word. So, the
`shift` is for the first Bit field and the `newshift` is for the second
one. Will modify the comment accordingly!

> > > +struct owl_dma_lli_hw {
> > > +	u32	next_lli;	/* physical address of the next link list */
> > > +	u32	saddr;		/* source physical address */
> > > +	u32	daddr;		/* destination physical address */
> > > +	u32	flen:20;	/* frame length */
> > > +	u32	fcnt:12;	/* frame count */
> > > +	u32	src_stride;	/* source stride */
> > > +	u32	dst_stride;	/* destination stride */
> > > +	u32	ctrla;		/* dma_mode and linklist ctrl */
> > > +	u32	ctrlb;		/* interrupt control */
> > > +	u32	const_num;	/* data for constant fill */
> > 
> > i think you can skip comment here or kernel-doc style, please pick one
> > and not both
> > 

Ack. Will remove the per member comment.

> > > +struct owl_dma_txd {
> > > +	struct virt_dma_desc	vd;
> > > +	struct list_head	lli_list;
> > 
> > why do you need this list. vd has its own list as well!
> > 

Yes, but vd's list is named as node and that will create ambiguity since we
will be using it as a list. So, I guess we would need lli_list.

> > > +static void pchan_update(void __iomem *reg, u32 val, bool state)
> > 
> > why does this not use pchan as arg as the name of API implies (you did
> > that on the other two)
> > 

I wanted to just update the reg without using too many arguments.
Anyway, I can modify it to use pchan as the argument.

> > > +static inline int owl_dma_cfg_lli(struct owl_dma_vchan *vchan,
> > > +				  struct owl_dma_lli *lli,
> > > +				  dma_addr_t src, dma_addr_t dst,
> > > +				  u32 len, enum dma_transfer_direction dir)
> > > +{
> > > +	struct owl_dma_lli_hw *hw = &lli->hw;
> > > +	u32 mode;
> > > +
> > > +	mode = OWL_DMA_MODE_PW(0);
> > > +
> > > +	switch (dir) {
> > > +	case DMA_MEM_TO_MEM:
> > > +		mode |= OWL_DMA_MODE_TS(0) | OWL_DMA_MODE_ST_DCU |
> > > +			OWL_DMA_MODE_DT_DCU | OWL_DMA_MODE_SAM_INC |
> > > +			OWL_DMA_MODE_DAM_INC;
> > > +
> > > +		break;
> > > +	default:
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	hw->next_lli = 0; /* One link list by default */
> > > +	hw->saddr = src;
> > > +	hw->daddr = dst;
> > > +
> > > +	hw->fcnt = 1; /* Frame count fixed as 1 */
> > > +	hw->flen = len; /* Max frame length is 1MB */
> > 
> > are you checking that somewhere?
> > 

No need to check since we allow only max size in the caller. The
following line does the job:

bytes = min_t(size_t, (len - offset), OWL_DMA_FRAME_MAX_LENGTH);

> > > +static struct owl_dma_pchan *owl_dma_get_pchan(struct owl_dma *od,
> > > +					       struct owl_dma_vchan *vchan)
> > > +{
> > > +	struct owl_dma_pchan *pchan;
> > > +	unsigned long flags;
> > > +	int i;
> > > +
> > > +	for (i = 0; i < od->nr_pchans; i++) {
> > > +		pchan = &od->pchans[i];
> > > +
> > > +		spin_lock_irqsave(&pchan->lock, flags);
> > > +		if (!pchan->vchan) {
> > > +			pchan->vchan = vchan;
> > > +			spin_unlock_irqrestore(&pchan->lock, flags);
> > > +			break;
> > > +		}
> > > +
> > > +		spin_unlock_irqrestore(&pchan->lock, flags);
> > > +	}
> > > +
> > > +	if (i == od->nr_pchans) {
> > > +		/* No physical channel available, cope with it */
> > > +		dev_dbg(od->dma.dev, "no physical channel available\n");
> > 
> > not sure about this. The concept of virt-chan is that you would submit a
> > transaction to controller for different channels. If channel is busy the
> > txn is simply queued up. You do not need a _free_ channel
> > 

Okay. I guess I should remove the error message here. We are bailing out
if all of the channels are busy otherwise we will start the transactions
one by one with the help of ISR.

> > > +static void owl_dma_pause_pchan(struct owl_dma_pchan *pchan)
> > > +{
> > > +	pchan_writel(pchan, 1, OWL_DMAX_PAUSE);
> > > +}
> > > +
> > > +static void owl_dma_resume_pchan(struct owl_dma_pchan *pchan)
> > > +{
> > > +	pchan_writel(pchan, 0, OWL_DMAX_PAUSE);
> > > +}
> > 
> > mempcy and pause/resume dont make much sense, are you sure you want that
> > here and not later on slave copy
> > 

Okay, will remove these for now and add it in slave support.

> > > +static void owl_dma_free_txd(struct owl_dma *od, struct owl_dma_txd *txd)
> > > +{
> > > +	struct owl_dma_lli *lli, *_lli;
> > > +
> > > +	if (unlikely(!txd))
> > > +		return;
> > > +
> > > +	list_for_each_entry_safe(lli, _lli, &txd->lli_list, node) {
> > > +		owl_dma_free_lli(od, lli);
> > > +	}
> > 
> > braces not required here
> > 

Ack.

> > > +static int owl_dma_remove(struct platform_device *pdev)
> > > +{
> > > +	struct owl_dma *od = platform_get_drvdata(pdev);
> > > +
> > > +	of_dma_controller_free(pdev->dev.of_node);

Oops. This is not needed here.

> > > +	dma_async_device_unregister(&od->dma);
> > > +
> > > +	/* Mask all interrupts for this execution environment */
> > > +	dma_writel(od, 0x0, OWL_DMA_IRQ_EN0);
> > > +	owl_dma_free(od);
> > 
> > the tasklets are killed but irqs can still run and trigger the irqs :)

Okay, will add devm_free_irq.

Thanks,
Mani

> > -- 
> > ~Vinod
> 
> -- 
> ~Vinod
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux