RE: [PATCH v3 3/3] dmaengine: vdma: Add clock support

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

 




Hi Soren,

> -----Original Message-----
> From: Sören Brinkmann [mailto:soren.brinkmann@xxxxxxxxxx]
> Sent: Thursday, April 21, 2016 9:52 PM
> To: Appana Durga Kedareswara Rao <appanad@xxxxxxxxxx>
> Cc: robh+dt@xxxxxxxxxx; pawel.moll@xxxxxxx; mark.rutland@xxxxxxx;
> ijc+devicetree@xxxxxxxxxxxxxx; galak@xxxxxxxxxxxxxx; Michal Simek
> <michals@xxxxxxxxxx>; vinod.koul@xxxxxxxxx; dan.j.williams@xxxxxxxxx;
> Appana Durga Kedareswara Rao <appanad@xxxxxxxxxx>;
> moritz.fischer@xxxxxxxxx; laurent.pinchart@xxxxxxxxxxxxxxxx;
> luis@xxxxxxxxxxxxxxxxx; Anirudha Sarangi <anirudh@xxxxxxxxxx>; Punnaiah
> Choudary Kalluri <punnaia@xxxxxxxxxx>; Shubhrajyoti Datta
> <shubhraj@xxxxxxxxxx>; devicetree@xxxxxxxxxxxxxxx; linux-arm-
> kernel@xxxxxxxxxxxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx;
> dmaengine@xxxxxxxxxxxxxxx
> Subject: Re: [PATCH v3 3/3] dmaengine: vdma: Add clock support
> 
> On Thu, 2016-04-21 at 16:08:38 +0530, Kedareswara rao Appana wrote:
> > Added basic clock support for axi dma's.
> > The clocks are requested at probe and released at remove.
> >
> > Reviewed-by: Shubhrajyoti Datta <shubhraj@xxxxxxxxxx>
> > Signed-off-by: Kedareswara rao Appana <appanad@xxxxxxxxxx>
> > ---
> > Changes for v3:
> > ---> Added clock support for all the AXI DMA's.
> > ---> Fixed clk_unprepare leak during probe fail as suggested by Moritz.
> > ---> Fixed comment driver specifically asks for the clocks it needs
> > ---> and return
> > an error if a mandatory clock is missing as suggested by soren.
> > Changes for v2:
> > ---> None.
> >
> >  drivers/dma/xilinx/xilinx_vdma.c | 225
> > ++++++++++++++++++++++++++++++++++++++-
> >  1 file changed, 223 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/dma/xilinx/xilinx_vdma.c
> > b/drivers/dma/xilinx/xilinx_vdma.c
> > index 5bfaa32..41bb5b3 100644
> > --- a/drivers/dma/xilinx/xilinx_vdma.c
> > +++ b/drivers/dma/xilinx/xilinx_vdma.c
> > @@ -44,6 +44,7 @@
> >  #include <linux/of_platform.h>
> >  #include <linux/of_irq.h>
> >  #include <linux/slab.h>
> > +#include <linux/clk.h>
> >
> >  #include "../dmaengine.h"
> >
> > @@ -344,6 +345,9 @@ struct xilinx_dma_chan {
> >
> >  struct dma_config {
> >  	enum xdma_ip_type dmatype;
> > +	int (*clk_init)(struct platform_device *pdev, struct clk **axi_clk,
> > +			struct clk **tx_clk, struct clk **txs_clk,
> > +			struct clk **rx_clk, struct clk **rxs_clk);
> >  };
> >
> >  /**
> > @@ -365,7 +369,13 @@ struct xilinx_dma_device {
> >  	bool has_sg;
> >  	u32 flush_on_fsync;
> >  	bool ext_addr;
> > +	struct platform_device  *pdev;
> >  	const struct dma_config *dma_config;
> > +	struct clk *axi_clk;
> > +	struct clk *tx_clk;
> > +	struct clk *txs_clk;
> > +	struct clk *rx_clk;
> > +	struct clk *rxs_clk;
> >  };
> 
> the struct members could be documented

Ok Will document in the next version...

> 
> >
> >  /* Macros */
> > @@ -1757,6 +1767,200 @@ static void xilinx_dma_chan_remove(struct
> xilinx_dma_chan *chan)
> >  	list_del(&chan->common.device_node);
> >  }
> >
> > +static int axidma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
> > +			    struct clk **tx_clk, struct clk **rx_clk,
> > +			    struct clk **sg_clk, struct clk **tmp_clk) {
> > +	int err;
> > +
> > +	*tmp_clk = NULL;
> > +
> > +	*axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk");
> > +	if (IS_ERR(*axi_clk)) {
> > +		err = PTR_ERR(*axi_clk);
> > +		dev_err(&pdev->dev, "failed to get axi_aclk (%u)\n", err);
> > +		return err;
> > +	}
> > +
> > +	*tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk");
> > +	if (IS_ERR(*tx_clk))
> > +		*tx_clk = NULL;
> > +
> > +	*rx_clk = devm_clk_get(&pdev->dev, "m_axi_s2mm_aclk");
> > +	if (IS_ERR(*rx_clk))
> > +		*rx_clk = NULL;
> > +
> > +	*sg_clk = devm_clk_get(&pdev->dev, "m_axi_sg_aclk");
> > +	if (IS_ERR(*sg_clk))
> > +		*sg_clk = NULL;
> > +
> > +
> > +	err = clk_prepare_enable(*axi_clk);
> 
> Should this be called if you know that the pointer might be NULL?

It is a mandatory clock and if this clk is not there in DT I am already returning error...
I didn't get your question could you please elaborate???
 
> 
> > +	if (err) {
> > +		dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err);
> > +		return err;
> > +	}
> > +
> > +	err = clk_prepare_enable(*tx_clk);
> > +	if (err) {
> > +		dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
> > +		goto err_disable_axiclk;
> > +	}
> > +
> > +	err = clk_prepare_enable(*rx_clk);
> > +	if (err) {
> > +		dev_err(&pdev->dev, "failed to enable txs_clk (%u)\n", err);
> > +		goto err_disable_txclk;
> > +	}
> > +
> > +	err = clk_prepare_enable(*sg_clk);
> > +	if (err) {
> > +		dev_err(&pdev->dev, "failed to enable rxs_clk (%u)\n", err);
> > +		goto err_disable_rxclk;
> > +	}
> > +
> > +	return 0;
> > +
> > +err_disable_rxclk:
> > +	clk_disable_unprepare(*rx_clk);
> > +err_disable_txclk:
> > +	clk_disable_unprepare(*tx_clk);
> > +err_disable_axiclk:
> > +	clk_disable_unprepare(*axi_clk);
> > +
> > +	return err;
> > +}
> > +
> > +static int axicdma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
> > +			    struct clk **dev_clk, struct clk **tmp_clk,
> > +			    struct clk **tmp1_clk, struct clk **tmp2_clk) {
> > +	int err;
> > +
> > +	*tmp_clk = NULL;
> > +	*tmp1_clk = NULL;
> > +	*tmp2_clk = NULL;
> > +
> > +	*axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk");
> > +	if (IS_ERR(*axi_clk)) {
> > +		err = PTR_ERR(*axi_clk);
> > +		dev_err(&pdev->dev, "failed to get axi_aclk (%u)\n", err);
> > +		return err;
> > +	}
> > +
> > +	*dev_clk = devm_clk_get(&pdev->dev, "m_axi_aclk");
> > +	if (IS_ERR(*dev_clk))
> > +		*dev_clk = NULL;
> 
> This is a required clock according to binding but a failure is ignored here.

Hmm nice catch will fix in next version...

> 
> > +
> > +
> > +	err = clk_prepare_enable(*axi_clk);
> > +	if (err) {
> > +		dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err);
> > +		return err;
> > +	}
> > +
> > +	err = clk_prepare_enable(*dev_clk);
> > +	if (err) {
> > +		dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
> > +		goto err_disable_axiclk;
> > +	}
> > +
> > +
> > +	return 0;
> > +
> > +err_disable_axiclk:
> > +	clk_disable_unprepare(*axi_clk);
> > +
> > +	return err;
> > +}
> > +
> > +static int axivdma_clk_init(struct platform_device *pdev, struct clk **axi_clk,
> > +			    struct clk **tx_clk, struct clk **txs_clk,
> > +			    struct clk **rx_clk, struct clk **rxs_clk) {
> > +	int err;
> > +
> > +	*axi_clk = devm_clk_get(&pdev->dev, "s_axi_lite_aclk");
> > +	if (IS_ERR(*axi_clk)) {
> > +		err = PTR_ERR(*axi_clk);
> > +		dev_err(&pdev->dev, "failed to get axi_aclk (%u)\n", err);
> > +		return err;
> > +	}
> > +
> > +	*tx_clk = devm_clk_get(&pdev->dev, "m_axi_mm2s_aclk");
> > +	if (IS_ERR(*tx_clk))
> > +		*tx_clk = NULL;
> > +
> > +	*txs_clk = devm_clk_get(&pdev->dev, "m_axis_mm2s_aclk");
> > +	if (IS_ERR(*txs_clk))
> > +		*txs_clk = NULL;
> > +
> > +	*rx_clk = devm_clk_get(&pdev->dev, "m_axi_s2mm_aclk");
> > +	if (IS_ERR(*rx_clk))
> > +		*rx_clk = NULL;
> > +
> > +	*rxs_clk = devm_clk_get(&pdev->dev, "s_axis_s2mm_aclk");
> > +	if (IS_ERR(*rxs_clk))
> > +		*rxs_clk = NULL;
> > +
> > +
> > +	err = clk_prepare_enable(*axi_clk);
> > +	if (err) {
> > +		dev_err(&pdev->dev, "failed to enable axi_clk (%u)\n", err);
> > +		return err;
> > +	}
> > +
> > +	err = clk_prepare_enable(*tx_clk);
> > +	if (err) {
> > +		dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", err);
> > +		goto err_disable_axiclk;
> > +	}
> > +
> > +	err = clk_prepare_enable(*txs_clk);
> > +	if (err) {
> > +		dev_err(&pdev->dev, "failed to enable txs_clk (%u)\n", err);
> > +		goto err_disable_txclk;
> > +	}
> > +
> > +	err = clk_prepare_enable(*rx_clk);
> > +	if (err) {
> > +		dev_err(&pdev->dev, "failed to enable rx_clk (%u)\n", err);
> > +		goto err_disable_txsclk;
> > +	}
> > +
> > +	err = clk_prepare_enable(*rxs_clk);
> > +	if (err) {
> > +		dev_err(&pdev->dev, "failed to enable rxs_clk (%u)\n", err);
> > +		goto err_disable_rxclk;
> > +	}
> > +
> > +	return 0;
> > +
> > +err_disable_rxclk:
> > +	clk_disable_unprepare(*rx_clk);
> > +err_disable_txsclk:
> > +	clk_disable_unprepare(*txs_clk);
> > +err_disable_txclk:
> > +	clk_disable_unprepare(*tx_clk);
> > +err_disable_axiclk:
> > +	clk_disable_unprepare(*axi_clk);
> > +
> > +	return err;
> > +}
> > +
> > +static void xdma_disable_allclks(struct xilinx_dma_device *xdev) {
> > +	if (!IS_ERR(xdev->rxs_clk))
> 
> The init functions set the optional clocks to NULL if not present. So, these
> pointers should be valid or NULL, but not an error pointer (I think NULL is not
> considered an error pointer as there is a IS_ERR_OR_NULL macro).

Ok will remove IS_ERR checks...

> 
> > +		clk_disable_unprepare(xdev->rxs_clk);
> > +	if (!IS_ERR(xdev->rx_clk))
> > +		clk_disable_unprepare(xdev->rx_clk);
> > +	if (!IS_ERR(xdev->txs_clk))
> > +		clk_disable_unprepare(xdev->txs_clk);
> > +	if (!IS_ERR(xdev->tx_clk))
> > +		clk_disable_unprepare(xdev->tx_clk);
> > +	clk_disable_unprepare(xdev->axi_clk);
> > +}
> > +
> >  /**
> >   * xilinx_dma_chan_probe - Per Channel Probing
> >   * It get channel features from the device tree entry and @@ -1900,14
> > +2104,17 @@ static struct dma_chan *of_dma_xilinx_xlate(struct
> > of_phandle_args *dma_spec,
> >
> >  static const struct dma_config axidma_config = {
> >  	.dmatype = XDMA_TYPE_AXIDMA,
> > +	.clk_init = axidma_clk_init,
> >  };
> >
> >  static const struct dma_config axicdma_config = {
> >  	.dmatype = XDMA_TYPE_CDMA,
> > +	.clk_init = axicdma_clk_init,
> >  };
> >
> >  static const struct dma_config axivdma_config = {
> >  	.dmatype = XDMA_TYPE_VDMA,
> > +	.clk_init = axivdma_clk_init,
> >  };
> >
> >  static const struct of_device_id xilinx_dma_of_ids[] = { @@ -1926,9
> > +2133,13 @@ MODULE_DEVICE_TABLE(of, xilinx_dma_of_ids);
> >   */
> >  static int xilinx_dma_probe(struct platform_device *pdev)  {
> > +	int (*clk_init)(struct platform_device *, struct clk **, struct clk **,
> > +			struct clk **, struct clk **, struct clk **)
> > +					= axivdma_clk_init;
> >  	struct device_node *node = pdev->dev.of_node;
> >  	struct xilinx_dma_device *xdev;
> >  	struct device_node *child, *np = pdev->dev.of_node;
> > +	struct clk *axi_clk, *tx_clk, *txs_clk, *rx_clk, *rxs_clk;
> 
> Are these local vars ever transferred into the struct xilinx_dma_device (I actually
> think you can directly use the struct instead of these locals).

Ok will fix in the next version...

Regards,
Kedar.

> 
> >  	struct resource *io;
> >  	u32 num_frames, addr_width;
> >  	int i, err;
> > @@ -1943,10 +2154,16 @@ static int xilinx_dma_probe(struct
> platform_device *pdev)
> >  		const struct of_device_id *match;
> >
> >  		match = of_match_node(xilinx_dma_of_ids, np);
> > -		if (match && match->data)
> > +		if (match && match->data) {
> >  			xdev->dma_config = match->data;
> > +			clk_init = xdev->dma_config->clk_init;
> > +		}
> >  	}
> >
> > +	err = clk_init(pdev, &axi_clk, &tx_clk, &txs_clk, &rx_clk, &rxs_clk);
> > +	if (err)
> > +		return err;
> > +
> >  	/* Request and map I/O memory */
> >  	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >  	xdev->regs = devm_ioremap_resource(&pdev->dev, io); @@ -2019,7
> > +2236,7 @@ static int xilinx_dma_probe(struct platform_device *pdev)
> >  	for_each_child_of_node(node, child) {
> >  		err = xilinx_dma_chan_probe(xdev, child);
> >  		if (err < 0)
> > -			goto error;
> > +			goto disable_clks;
> >  	}
> >
> >  	if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) { @@ -2043,6
> > +2260,8 @@ static int xilinx_dma_probe(struct platform_device *pdev)
> >
> >  	return 0;
> >
> > +disable_clks:
> > +	xdma_disable_allclks(xdev);
> >  error:
> >  	for (i = 0; i < XILINX_DMA_MAX_CHANS_PER_DEVICE; i++)
> >  		if (xdev->chan[i])
> > @@ -2070,6 +2289,8 @@ static int xilinx_dma_remove(struct
> platform_device *pdev)
> >  		if (xdev->chan[i])
> >  			xilinx_dma_chan_remove(xdev->chan[i]);
> >
> > +	xdma_disable_allclks(xdev);
> > +
> >  	return 0;
> >  }
> 
> Sören
��.n��������+%������w��{.n����z�{��ܨ}���Ơz�j:+v�����w����ޙ��&�)ߡ�a����z�ޗ���ݢj��w�f




[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