Re: [PATCH v3 2/2] dmaengine: uniphier-mdmac: add UniPhier MIO DMAC driver

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

 



On 13-09-18, 09:51, Masahiro Yamada wrote:

> +#define UNIPHIER_MDMAC_CH_IRQ_STAT	0x010	// current hw status (RO)
> +#define UNIPHIER_MDMAC_CH_IRQ_REQ	0x014	// latched STAT (WOC)
> +#define UNIPHIER_MDMAC_CH_IRQ_EN	0x018	// IRQ enable mask
> +#define UNIPHIER_MDMAC_CH_IRQ_DET	0x01c	// REQ & EN (RO)
> +#define   UNIPHIER_MDMAC_CH_IRQ__ABORT		BIT(13)
> +#define   UNIPHIER_MDMAC_CH_IRQ__DONE		BIT(1)

why notation if UNIPHIER_MDMAC_CH_IRQ__FOO ?

> +#define UNIPHIER_MDMAC_CH_SRC_MODE	0x020	// mode of source
> +#define UNIPHIER_MDMAC_CH_DEST_MODE	0x024	// mode of destination
> +#define   UNIPHIER_MDMAC_CH_MODE__ADDR_INC	(0 << 4)
> +#define   UNIPHIER_MDMAC_CH_MODE__ADDR_DEC	(1 << 4)
> +#define   UNIPHIER_MDMAC_CH_MODE__ADDR_FIXED	(2 << 4)
> +#define UNIPHIER_MDMAC_CH_SRC_ADDR	0x028	// source address
> +#define UNIPHIER_MDMAC_CH_DEST_ADDR	0x02c	// destination address
> +#define UNIPHIER_MDMAC_CH_SIZE		0x030	// transfer bytes

Please use /* comment */ style for these

> +/* mc->vc.lock must be held by caller */
> +static struct uniphier_mdmac_desc *__uniphier_mdmac_next_desc(
> +						struct uniphier_mdmac_chan *mc)

this can be made to look better by:

static struct uniphier_mdmac_desc *
__uniphier_mdmac_next_desc(struct uniphier_mdmac_chan *mc)

Btw why leading __ for function name here and other places?

> +{
> +	struct virt_dma_desc *vd;
> +
> +	vd = vchan_next_desc(&mc->vc);
> +	if (!vd) {
> +		mc->md = NULL;
> +		return NULL;
> +	}
> +
> +	list_del(&vd->node);
> +
> +	mc->md = to_uniphier_mdmac_desc(vd);
> +
> +	return mc->md;
> +}
> +
> +/* mc->vc.lock must be held by caller */
> +static void __uniphier_mdmac_handle(struct uniphier_mdmac_chan *mc,
> +				    struct uniphier_mdmac_desc *md)

please align this to previous line opening brace (hint checkpatch with
--strict option will give you the warning)

> +static irqreturn_t uniphier_mdmac_interrupt(int irq, void *dev_id)
> +{
> +	struct uniphier_mdmac_chan *mc = dev_id;
> +	struct uniphier_mdmac_desc *md;
> +	irqreturn_t ret = IRQ_HANDLED;
> +	u32 irq_stat;
> +
> +	spin_lock(&mc->vc.lock);
> +
> +	irq_stat = readl(mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_DET);
> +
> +	/*
> +	 * Some channels share a single interrupt line. If the IRQ status is 0,
> +	 * this is probably triggered by a different channel.
> +	 */
> +	if (!irq_stat) {
> +		ret = IRQ_NONE;
> +		goto out;
> +	}
> +
> +	/* write 1 to clear */
> +	writel(irq_stat, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ);
> +
> +	/*
> +	 * UNIPHIER_MDMAC_CH_IRQ__DONE interrupt is asserted even when the DMA
> +	 * is aborted.  To distinguish the normal completion and the abort,
                     ^^^^
double space..

> +static int uniphier_mdmac_config(struct dma_chan *chan,
> +				 struct dma_slave_config *config)
> +{
> +	/* Nothing in struct dma_slave_config is configurable. */
> +	return 0;
> +}

I dont think config callback is mandatory, so we can drop this

> +static enum dma_status uniphier_mdmac_tx_status(struct dma_chan *chan,
> +						dma_cookie_t cookie,
> +						struct dma_tx_state *txstate)
> +{
> +	struct virt_dma_chan *vc;
> +	struct virt_dma_desc *vd;
> +	struct uniphier_mdmac_chan *mc;
> +	struct uniphier_mdmac_desc *md = NULL;
> +	enum dma_status stat;
> +	unsigned long flags;
> +
> +	stat = dma_cookie_status(chan, cookie, txstate);
> +	/* Return immediately if we do not need to compute the residue. */
> +	if (stat == DMA_COMPLETE || !txstate)
> +		return stat;
> +
> +	vc = to_virt_chan(chan);
> +
> +	spin_lock_irqsave(&vc->lock, flags);
> +
> +	mc = to_uniphier_mdmac_chan(vc);
> +
> +	if (mc->md && mc->md->vd.tx.cookie == cookie)
> +		md = mc->md;
> +
> +	if (!md) {
> +		vd = vchan_find_desc(vc, cookie);
> +		if (vd)
> +			md = to_uniphier_mdmac_desc(vd);
> +	}

in both of these cases you are calling __uniphier_mdmac_get_residue()
which reads the register and updates. But I think you should read
register only in the first case when descriptor is submitted and not in
latter case when descriptor is queued

> +static int uniphier_mdmac_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct uniphier_mdmac_device *mdev;
> +	struct dma_device *ddev;
> +	struct resource *res;
> +	int nr_chans, ret, i;
> +
> +	nr_chans = platform_irq_count(pdev);
> +	if (nr_chans < 0)
> +		return nr_chans;
> +
> +	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
> +	if (ret)
> +		return ret;
> +
> +	mdev = devm_kzalloc(dev, struct_size(mdev, channels, nr_chans),
> +			    GFP_KERNEL);
> +	if (!mdev)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	mdev->reg_base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(mdev->reg_base))
> +		return PTR_ERR(mdev->reg_base);
> +
> +	mdev->clk = devm_clk_get(dev, NULL);
> +	if (IS_ERR(mdev->clk)) {
> +		dev_err(dev, "failed to get clock\n");
> +		return PTR_ERR(mdev->clk);
> +	}
> +
> +	ret = clk_prepare_enable(mdev->clk);
> +	if (ret)
> +		return ret;
> +
> +	ddev = &mdev->ddev;
> +	ddev->dev = dev;
> +	dma_cap_set(DMA_PRIVATE, ddev->cap_mask);
> +	ddev->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED);
> +	ddev->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED);

undefined?

> +static int uniphier_mdmac_remove(struct platform_device *pdev)
> +{
> +	struct uniphier_mdmac_device *mdev = platform_get_drvdata(pdev);
> +
> +	of_dma_controller_free(pdev->dev.of_node);
> +	dma_async_device_unregister(&mdev->ddev);
> +	clk_disable_unprepare(mdev->clk);

at this point your irq is registered and can be fired, the tasklets are
not killed :(
-- 
~Vinod



[Index of Archives]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux PCI]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux