Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753113AbcDUQcx (ORCPT ); Thu, 21 Apr 2016 12:32:53 -0400 Received: from mail-sn1nam02on0068.outbound.protection.outlook.com ([104.47.36.68]:63872 "EHLO NAM02-SN1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751783AbcDUQcv (ORCPT ); Thu, 21 Apr 2016 12:32:51 -0400 Authentication-Results: spf=pass (sender IP is 149.199.60.100) smtp.mailfrom=xilinx.com; vger.kernel.org; dkim=none (message not signed) header.d=none;vger.kernel.org; dmarc=bestguesspass action=none header.from=xilinx.com; From: Appana Durga Kedareswara Rao To: Soren Brinkmann CC: "robh+dt@kernel.org" , "pawel.moll@arm.com" , "mark.rutland@arm.com" , "ijc+devicetree@hellion.org.uk" , "galak@codeaurora.org" , Michal Simek , "vinod.koul@intel.com" , "dan.j.williams@intel.com" , "moritz.fischer@ettus.com" , "laurent.pinchart@ideasonboard.com" , "luis@debethencourt.com" , Anirudha Sarangi , Punnaiah Choudary Kalluri , Shubhrajyoti Datta , "devicetree@vger.kernel.org" , "linux-arm-kernel@lists.infradead.org" , "linux-kernel@vger.kernel.org" , "dmaengine@vger.kernel.org" Subject: RE: [PATCH v3 3/3] dmaengine: vdma: Add clock support Thread-Topic: [PATCH v3 3/3] dmaengine: vdma: Add clock support Thread-Index: AQHRm7oBw54uslpveEWBfoSSWvBadJ+UFkSAgACHnpA= Date: Thu, 21 Apr 2016 16:32:44 +0000 Message-ID: References: <1461235118-800-1-git-send-email-appanad@xilinx.com> <1461235118-800-4-git-send-email-appanad@xilinx.com> <20160421162153.GZ7128@xsjsorenbubuntu> In-Reply-To: <20160421162153.GZ7128@xsjsorenbubuntu> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [172.23.228.198] Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 X-RCIS-Action: ALLOW X-TM-AS-Product-Ver: IMSS-7.1.0.1224-8.0.0.1202-22274.005 X-TM-AS-User-Approved-Sender: Yes;Yes X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:149.199.60.100;IPV:NLI;CTRY:US;EFV:NLI;SFV:NSPM;SFS:(10009020)(6009001)(2980300002)(438002)(24454002)(199003)(13464003)(189002)(377454003)(377424004)(87936001)(106466001)(6806005)(81166005)(55846006)(106116001)(50466002)(2906002)(63266004)(4326007)(76176999)(54356999)(5250100002)(5008740100001)(50986999)(11100500001)(86362001)(19580405001)(19580395003)(23676002)(2920100001)(2900100001)(47776003)(5004730100002)(1220700001)(1096002)(33656002)(2950100001)(102836003)(3846002)(586003)(189998001)(5003600100002)(6116002)(92566002)(4001450100002)(107986001);DIR:OUT;SFP:1101;SCL:1;SRVR:SN1NAM02HT127;H:xsj-pvapsmtpgw02;FPR:;SPF:Pass;MLV:sfv;A:1;MX:1;LANG:en; X-MS-Office365-Filtering-Correlation-Id: f0349669-6612-4ae8-368f-08d36a029399 X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:(8251501002);SRVR:SN1NAM02HT127; X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(9101521045)(601004)(2401047)(13018025)(13023025)(5005006)(13015025)(13017025)(8121501046)(13024025)(3002001)(10201501046);SRVR:SN1NAM02HT127;BCL:0;PCL:0;RULEID:;SRVR:SN1NAM02HT127; X-Forefront-PRVS: 091949432C X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Apr 2016 16:32:48.1892 (UTC) X-MS-Exchange-CrossTenant-Id: 657af505-d5df-48d0-8300-c31994686c5c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=657af505-d5df-48d0-8300-c31994686c5c;Ip=[149.199.60.100];Helo=[xsj-pvapsmtpgw02] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN1NAM02HT127 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: 8bit X-MIME-Autoconverted: from base64 to 8bit by mail.home.local id u3LGX16F011113 Content-Length: 11937 Lines: 390 Hi Soren, > -----Original Message----- > From: Sören Brinkmann [mailto:soren.brinkmann@xilinx.com] > Sent: Thursday, April 21, 2016 9:52 PM > To: Appana Durga Kedareswara Rao > Cc: robh+dt@kernel.org; pawel.moll@arm.com; mark.rutland@arm.com; > ijc+devicetree@hellion.org.uk; galak@codeaurora.org; Michal Simek > ; vinod.koul@intel.com; dan.j.williams@intel.com; > Appana Durga Kedareswara Rao ; > moritz.fischer@ettus.com; laurent.pinchart@ideasonboard.com; > luis@debethencourt.com; Anirudha Sarangi ; Punnaiah > Choudary Kalluri ; Shubhrajyoti Datta > ; devicetree@vger.kernel.org; linux-arm- > kernel@lists.infradead.org; linux-kernel@vger.kernel.org; > dmaengine@vger.kernel.org > 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 > > Signed-off-by: Kedareswara rao Appana > > --- > > 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 > > #include > > #include > > +#include > > > > #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