From: daniel.thompson@linaro.org (Daniel Thompson)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v2 2/4] dmaengine: Add STM32 DMA driver
Date: Tue, 13 Oct 2015 15:34:49 +0100 [thread overview]
Message-ID: <561D1689.90703@linaro.org> (raw)
In-Reply-To: <1444745127-1105-3-git-send-email-cedric.madianga@gmail.com>
On 13/10/15 15:05, M'boumba Cedric Madianga wrote:
> This patch adds support for the STM32 DMA controller.
>
> Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
> ---
> drivers/dma/Kconfig | 12 +
> drivers/dma/Makefile | 1 +
> drivers/dma/stm32-dma.c | 1175 +++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 1188 insertions(+)
> create mode 100644 drivers/dma/stm32-dma.c
> diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
> new file mode 100644
> index 0000000..031bab7
> --- /dev/null
> +++ b/drivers/dma/stm32-dma.c
> +enum stm32_dma_width {
> + STM32_DMA_BYTE,
> + STM32_DMA_HALF_WORD,
> + STM32_DMA_WORD,
> +};
> +
> +enum stm32_dma_burst_size {
> + STM32_DMA_BURST_SINGLE,
> + STM32_DMA_BURST_INCR4,
> + STM32_DMA_BURST_INCR8,
> + STM32_DMA_BURST_INCR16,
> +};
> +
> +enum stm32_dma_channel_id {
> + STM32_DMA_CHANNEL0,
> + STM32_DMA_CHANNEL1,
> + STM32_DMA_CHANNEL2,
> + STM32_DMA_CHANNEL3,
> + STM32_DMA_CHANNEL4,
> + STM32_DMA_CHANNEL5,
> + STM32_DMA_CHANNEL6,
> + STM32_DMA_CHANNEL7,
> +};
Why have (unused) enumerations to map numeric symbols to their own
natural values? Using normal integers would be better.
> +enum stm32_dma_request_id {
> + STM32_DMA_REQUEST0,
> + STM32_DMA_REQUEST1,
> + STM32_DMA_REQUEST2,
> + STM32_DMA_REQUEST3,
> + STM32_DMA_REQUEST4,
> + STM32_DMA_REQUEST5,
> + STM32_DMA_REQUEST6,
> + STM32_DMA_REQUEST7,
> +};
Ditto.
> +static void stm32_dma_dump_reg(struct stm32_dma_chan *chan)
> +{
> + struct stm32_dma_device *dmadev = stm32_dma_chan_get_dev(chan);
> +
> + dev_dbg(chan2dev(chan), "SCR: 0x%08x\n",
> + stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)));
> + dev_dbg(chan2dev(chan), "NDTR: 0x%08x\n",
> + stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id)));
> + dev_dbg(chan2dev(chan), "SPAR: 0x%08x\n",
> + stm32_dma_read(dmadev, STM32_DMA_SPAR(chan->id)));
> + dev_dbg(chan2dev(chan), "SM0AR: 0x%08x\n",
> + stm32_dma_read(dmadev, STM32_DMA_SM0AR(chan->id)));
> + dev_dbg(chan2dev(chan), "SM1AR: 0x%08x\n",
> + stm32_dma_read(dmadev, STM32_DMA_SM1AR(chan->id)));
> + dev_dbg(chan2dev(chan), "SFCR: 0x%08x\n",
> + stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id)));
> +}
Even at dev_dbg() this looks like log spam. This debug info gets issued
every time we set up a transfer!
> +static int stm32_dma_alloc_chan_resources(struct dma_chan *c)
> +{
> + struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
> + struct stm32_dma_device *dmadev = stm32_dma_chan_get_dev(chan);
> + int ret;
> +
> + chan->config_init = false;
> + ret = clk_prepare_enable(dmadev->clk);
> + if (ret < 0) {
> + dev_err(chan2dev(chan), "clk_prepare_enable failed: %d\n", ret);
> + return ret;
> + }
> +
> + ret = stm32_dma_disable_chan(chan);
> +
> + return ret;
> +}
The error path here looks like it will leak clock references.
> +static int stm32_dma_probe(struct platform_device *pdev)
> +{
> + struct stm32_dma_chan *chan;
> + struct stm32_dma_device *dmadev;
> + struct dma_device *dd;
> + const struct of_device_id *match;
> + unsigned int i;
> + struct resource *res;
> + int ret;
> +
> + match = of_match_device(stm32_dma_of_match, &pdev->dev);
> + if (!match) {
> + dev_err(&pdev->dev, "Error: No device match found\n");
> + return -ENODEV;
> + }
> +
> + dmadev = devm_kzalloc(&pdev->dev, sizeof(*dmadev), GFP_KERNEL);
> + if (!dmadev)
> + return -ENOMEM;
> +
> + dd = &dmadev->ddev;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + dmadev->base = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(dmadev->base))
> + return PTR_ERR(dmadev->base);
> +
> + dmadev->clk = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(dmadev->clk)) {
> + dev_err(&pdev->dev, "Error: Missing controller clock\n");
> + return PTR_ERR(dmadev->clk);
> + }
> +
> + dmadev->mem2mem = of_property_read_bool(pdev->dev.of_node,
> + "st,mem2mem");
> +
> + dmadev->rst = devm_reset_control_get(&pdev->dev, NULL);
> + if (!IS_ERR(dmadev->rst)) {
> + reset_control_assert(dmadev->rst);
> + udelay(2);
> + reset_control_deassert(dmadev->rst);
> + }
> +
> + dma_cap_set(DMA_SLAVE, dd->cap_mask);
> + dma_cap_set(DMA_PRIVATE, dd->cap_mask);
> + dma_cap_set(DMA_CYCLIC, dd->cap_mask);
> + dd->device_alloc_chan_resources = stm32_dma_alloc_chan_resources;
> + dd->device_free_chan_resources = stm32_dma_free_chan_resources;
> + dd->device_tx_status = stm32_dma_tx_status;
> + dd->device_issue_pending = stm32_dma_issue_pending;
> + dd->device_prep_slave_sg = stm32_dma_prep_slave_sg;
> + dd->device_prep_dma_cyclic = stm32_dma_prep_dma_cyclic;
> + dd->device_config = stm32_dma_slave_config;
> + dd->device_terminate_all = stm32_dma_terminate_all;
> + dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
> + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
> + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
> + dd->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
> + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
> + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
> + dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
> + dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
> + dd->dev = &pdev->dev;
> + INIT_LIST_HEAD(&dd->channels);
> +
> + if (dmadev->mem2mem) {
> + dma_cap_set(DMA_MEMCPY, dd->cap_mask);
> + dd->device_prep_dma_memcpy = stm32_dma_prep_dma_memcpy;
> + dd->directions |= BIT(DMA_MEM_TO_MEM);
> + }
> +
> + for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) {
> + chan = &dmadev->chan[i];
> + chan->id = i;
> + chan->vchan.desc_free = stm32_dma_desc_free;
> + vchan_init(&chan->vchan, dd);
> + }
> +
> + ret = dma_async_device_register(dd);
> + if (ret)
> + return ret;
> +
> + for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) {
> + chan = &dmadev->chan[i];
> + res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
> + if (!res) {
> + ret = -EINVAL;
> + dev_err(&pdev->dev, "No irq resource for chan %d\n", i);
> + goto err_unregister;
> + }
> + chan->irq = res->start;
> + ret = devm_request_irq(&pdev->dev, chan->irq,
> + stm32_dma_chan_irq, 0,
> + dev_name(chan2dev(chan)), chan);
> + if (ret) {
> + dev_err(&pdev->dev,
> + "request_irq failed with err %d channel %d\n",
> + ret, i);
> + goto err_unregister;
> + }
> + }
> +
> + ret = of_dma_controller_register(pdev->dev.of_node,
> + stm32_dma_of_xlate, dmadev);
> + if (ret < 0) {
> + dev_err(&pdev->dev,
> + "STM32 DMA DMA OF registration failed %d\n", ret);
> + goto err_unregister;
> + }
> +
> + platform_set_drvdata(pdev, dmadev);
> +
> + dev_info(&pdev->dev, "STM32 DMA driver registered\n");
> +
> + return 0;
> +
> +err_unregister:
> + dma_async_device_unregister(dd);
> +
> + return ret;
> +}
> +
> +static int stm32_dma_remove(struct platform_device *pdev)
> +{
> + struct stm32_dma_device *dmadev = platform_get_drvdata(pdev);
> +
> + of_dma_controller_free(pdev->dev.of_node);
> +
> + dma_async_device_unregister(&dmadev->ddev);
> +
> + clk_disable_unprepare(dmadev->clk);
What is the purpose of disabling/unpreparing the clock here?
stm32_dma_alloc_chan_resources() and stm32_dma_free_chan_resources()
should pair up and the clock should already be stopped.
Daniel.
WARNING: multiple messages have this Message-ID (diff)
From: Daniel Thompson <daniel.thompson-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
To: M'boumba Cedric Madianga
<cedric.madianga-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
pawel.moll-5wv7dgnIgG8@public.gmane.org,
mark.rutland-5wv7dgnIgG8@public.gmane.org,
ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg@public.gmane.org,
galak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org,
linux-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org,
vinod.koul-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
dmaengine-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: Re: [PATCH v2 2/4] dmaengine: Add STM32 DMA driver
Date: Tue, 13 Oct 2015 15:34:49 +0100 [thread overview]
Message-ID: <561D1689.90703@linaro.org> (raw)
In-Reply-To: <1444745127-1105-3-git-send-email-cedric.madianga-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On 13/10/15 15:05, M'boumba Cedric Madianga wrote:
> This patch adds support for the STM32 DMA controller.
>
> Signed-off-by: M'boumba Cedric Madianga <cedric.madianga-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---
> drivers/dma/Kconfig | 12 +
> drivers/dma/Makefile | 1 +
> drivers/dma/stm32-dma.c | 1175 +++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 1188 insertions(+)
> create mode 100644 drivers/dma/stm32-dma.c
> diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
> new file mode 100644
> index 0000000..031bab7
> --- /dev/null
> +++ b/drivers/dma/stm32-dma.c
> +enum stm32_dma_width {
> + STM32_DMA_BYTE,
> + STM32_DMA_HALF_WORD,
> + STM32_DMA_WORD,
> +};
> +
> +enum stm32_dma_burst_size {
> + STM32_DMA_BURST_SINGLE,
> + STM32_DMA_BURST_INCR4,
> + STM32_DMA_BURST_INCR8,
> + STM32_DMA_BURST_INCR16,
> +};
> +
> +enum stm32_dma_channel_id {
> + STM32_DMA_CHANNEL0,
> + STM32_DMA_CHANNEL1,
> + STM32_DMA_CHANNEL2,
> + STM32_DMA_CHANNEL3,
> + STM32_DMA_CHANNEL4,
> + STM32_DMA_CHANNEL5,
> + STM32_DMA_CHANNEL6,
> + STM32_DMA_CHANNEL7,
> +};
Why have (unused) enumerations to map numeric symbols to their own
natural values? Using normal integers would be better.
> +enum stm32_dma_request_id {
> + STM32_DMA_REQUEST0,
> + STM32_DMA_REQUEST1,
> + STM32_DMA_REQUEST2,
> + STM32_DMA_REQUEST3,
> + STM32_DMA_REQUEST4,
> + STM32_DMA_REQUEST5,
> + STM32_DMA_REQUEST6,
> + STM32_DMA_REQUEST7,
> +};
Ditto.
> +static void stm32_dma_dump_reg(struct stm32_dma_chan *chan)
> +{
> + struct stm32_dma_device *dmadev = stm32_dma_chan_get_dev(chan);
> +
> + dev_dbg(chan2dev(chan), "SCR: 0x%08x\n",
> + stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)));
> + dev_dbg(chan2dev(chan), "NDTR: 0x%08x\n",
> + stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id)));
> + dev_dbg(chan2dev(chan), "SPAR: 0x%08x\n",
> + stm32_dma_read(dmadev, STM32_DMA_SPAR(chan->id)));
> + dev_dbg(chan2dev(chan), "SM0AR: 0x%08x\n",
> + stm32_dma_read(dmadev, STM32_DMA_SM0AR(chan->id)));
> + dev_dbg(chan2dev(chan), "SM1AR: 0x%08x\n",
> + stm32_dma_read(dmadev, STM32_DMA_SM1AR(chan->id)));
> + dev_dbg(chan2dev(chan), "SFCR: 0x%08x\n",
> + stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id)));
> +}
Even at dev_dbg() this looks like log spam. This debug info gets issued
every time we set up a transfer!
> +static int stm32_dma_alloc_chan_resources(struct dma_chan *c)
> +{
> + struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
> + struct stm32_dma_device *dmadev = stm32_dma_chan_get_dev(chan);
> + int ret;
> +
> + chan->config_init = false;
> + ret = clk_prepare_enable(dmadev->clk);
> + if (ret < 0) {
> + dev_err(chan2dev(chan), "clk_prepare_enable failed: %d\n", ret);
> + return ret;
> + }
> +
> + ret = stm32_dma_disable_chan(chan);
> +
> + return ret;
> +}
The error path here looks like it will leak clock references.
> +static int stm32_dma_probe(struct platform_device *pdev)
> +{
> + struct stm32_dma_chan *chan;
> + struct stm32_dma_device *dmadev;
> + struct dma_device *dd;
> + const struct of_device_id *match;
> + unsigned int i;
> + struct resource *res;
> + int ret;
> +
> + match = of_match_device(stm32_dma_of_match, &pdev->dev);
> + if (!match) {
> + dev_err(&pdev->dev, "Error: No device match found\n");
> + return -ENODEV;
> + }
> +
> + dmadev = devm_kzalloc(&pdev->dev, sizeof(*dmadev), GFP_KERNEL);
> + if (!dmadev)
> + return -ENOMEM;
> +
> + dd = &dmadev->ddev;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + dmadev->base = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(dmadev->base))
> + return PTR_ERR(dmadev->base);
> +
> + dmadev->clk = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(dmadev->clk)) {
> + dev_err(&pdev->dev, "Error: Missing controller clock\n");
> + return PTR_ERR(dmadev->clk);
> + }
> +
> + dmadev->mem2mem = of_property_read_bool(pdev->dev.of_node,
> + "st,mem2mem");
> +
> + dmadev->rst = devm_reset_control_get(&pdev->dev, NULL);
> + if (!IS_ERR(dmadev->rst)) {
> + reset_control_assert(dmadev->rst);
> + udelay(2);
> + reset_control_deassert(dmadev->rst);
> + }
> +
> + dma_cap_set(DMA_SLAVE, dd->cap_mask);
> + dma_cap_set(DMA_PRIVATE, dd->cap_mask);
> + dma_cap_set(DMA_CYCLIC, dd->cap_mask);
> + dd->device_alloc_chan_resources = stm32_dma_alloc_chan_resources;
> + dd->device_free_chan_resources = stm32_dma_free_chan_resources;
> + dd->device_tx_status = stm32_dma_tx_status;
> + dd->device_issue_pending = stm32_dma_issue_pending;
> + dd->device_prep_slave_sg = stm32_dma_prep_slave_sg;
> + dd->device_prep_dma_cyclic = stm32_dma_prep_dma_cyclic;
> + dd->device_config = stm32_dma_slave_config;
> + dd->device_terminate_all = stm32_dma_terminate_all;
> + dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
> + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
> + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
> + dd->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
> + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
> + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
> + dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
> + dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
> + dd->dev = &pdev->dev;
> + INIT_LIST_HEAD(&dd->channels);
> +
> + if (dmadev->mem2mem) {
> + dma_cap_set(DMA_MEMCPY, dd->cap_mask);
> + dd->device_prep_dma_memcpy = stm32_dma_prep_dma_memcpy;
> + dd->directions |= BIT(DMA_MEM_TO_MEM);
> + }
> +
> + for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) {
> + chan = &dmadev->chan[i];
> + chan->id = i;
> + chan->vchan.desc_free = stm32_dma_desc_free;
> + vchan_init(&chan->vchan, dd);
> + }
> +
> + ret = dma_async_device_register(dd);
> + if (ret)
> + return ret;
> +
> + for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) {
> + chan = &dmadev->chan[i];
> + res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
> + if (!res) {
> + ret = -EINVAL;
> + dev_err(&pdev->dev, "No irq resource for chan %d\n", i);
> + goto err_unregister;
> + }
> + chan->irq = res->start;
> + ret = devm_request_irq(&pdev->dev, chan->irq,
> + stm32_dma_chan_irq, 0,
> + dev_name(chan2dev(chan)), chan);
> + if (ret) {
> + dev_err(&pdev->dev,
> + "request_irq failed with err %d channel %d\n",
> + ret, i);
> + goto err_unregister;
> + }
> + }
> +
> + ret = of_dma_controller_register(pdev->dev.of_node,
> + stm32_dma_of_xlate, dmadev);
> + if (ret < 0) {
> + dev_err(&pdev->dev,
> + "STM32 DMA DMA OF registration failed %d\n", ret);
> + goto err_unregister;
> + }
> +
> + platform_set_drvdata(pdev, dmadev);
> +
> + dev_info(&pdev->dev, "STM32 DMA driver registered\n");
> +
> + return 0;
> +
> +err_unregister:
> + dma_async_device_unregister(dd);
> +
> + return ret;
> +}
> +
> +static int stm32_dma_remove(struct platform_device *pdev)
> +{
> + struct stm32_dma_device *dmadev = platform_get_drvdata(pdev);
> +
> + of_dma_controller_free(pdev->dev.of_node);
> +
> + dma_async_device_unregister(&dmadev->ddev);
> +
> + clk_disable_unprepare(dmadev->clk);
What is the purpose of disabling/unpreparing the clock here?
stm32_dma_alloc_chan_resources() and stm32_dma_free_chan_resources()
should pair up and the clock should already be stopped.
Daniel.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
WARNING: multiple messages have this Message-ID (diff)
From: Daniel Thompson <daniel.thompson@linaro.org>
To: "M'boumba Cedric Madianga" <cedric.madianga@gmail.com>,
mcoquelin.stm32@gmail.com, robh+dt@kernel.org,
pawel.moll@arm.com, mark.rutland@arm.com,
ijc+devicetree@hellion.org.uk, galak@codeaurora.org,
linux@arm.linux.org.uk, vinod.koul@intel.com,
linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, dmaengine@vger.kernel.org
Subject: Re: [PATCH v2 2/4] dmaengine: Add STM32 DMA driver
Date: Tue, 13 Oct 2015 15:34:49 +0100 [thread overview]
Message-ID: <561D1689.90703@linaro.org> (raw)
In-Reply-To: <1444745127-1105-3-git-send-email-cedric.madianga@gmail.com>
On 13/10/15 15:05, M'boumba Cedric Madianga wrote:
> This patch adds support for the STM32 DMA controller.
>
> Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
> ---
> drivers/dma/Kconfig | 12 +
> drivers/dma/Makefile | 1 +
> drivers/dma/stm32-dma.c | 1175 +++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 1188 insertions(+)
> create mode 100644 drivers/dma/stm32-dma.c
> diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
> new file mode 100644
> index 0000000..031bab7
> --- /dev/null
> +++ b/drivers/dma/stm32-dma.c
> +enum stm32_dma_width {
> + STM32_DMA_BYTE,
> + STM32_DMA_HALF_WORD,
> + STM32_DMA_WORD,
> +};
> +
> +enum stm32_dma_burst_size {
> + STM32_DMA_BURST_SINGLE,
> + STM32_DMA_BURST_INCR4,
> + STM32_DMA_BURST_INCR8,
> + STM32_DMA_BURST_INCR16,
> +};
> +
> +enum stm32_dma_channel_id {
> + STM32_DMA_CHANNEL0,
> + STM32_DMA_CHANNEL1,
> + STM32_DMA_CHANNEL2,
> + STM32_DMA_CHANNEL3,
> + STM32_DMA_CHANNEL4,
> + STM32_DMA_CHANNEL5,
> + STM32_DMA_CHANNEL6,
> + STM32_DMA_CHANNEL7,
> +};
Why have (unused) enumerations to map numeric symbols to their own
natural values? Using normal integers would be better.
> +enum stm32_dma_request_id {
> + STM32_DMA_REQUEST0,
> + STM32_DMA_REQUEST1,
> + STM32_DMA_REQUEST2,
> + STM32_DMA_REQUEST3,
> + STM32_DMA_REQUEST4,
> + STM32_DMA_REQUEST5,
> + STM32_DMA_REQUEST6,
> + STM32_DMA_REQUEST7,
> +};
Ditto.
> +static void stm32_dma_dump_reg(struct stm32_dma_chan *chan)
> +{
> + struct stm32_dma_device *dmadev = stm32_dma_chan_get_dev(chan);
> +
> + dev_dbg(chan2dev(chan), "SCR: 0x%08x\n",
> + stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)));
> + dev_dbg(chan2dev(chan), "NDTR: 0x%08x\n",
> + stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id)));
> + dev_dbg(chan2dev(chan), "SPAR: 0x%08x\n",
> + stm32_dma_read(dmadev, STM32_DMA_SPAR(chan->id)));
> + dev_dbg(chan2dev(chan), "SM0AR: 0x%08x\n",
> + stm32_dma_read(dmadev, STM32_DMA_SM0AR(chan->id)));
> + dev_dbg(chan2dev(chan), "SM1AR: 0x%08x\n",
> + stm32_dma_read(dmadev, STM32_DMA_SM1AR(chan->id)));
> + dev_dbg(chan2dev(chan), "SFCR: 0x%08x\n",
> + stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id)));
> +}
Even at dev_dbg() this looks like log spam. This debug info gets issued
every time we set up a transfer!
> +static int stm32_dma_alloc_chan_resources(struct dma_chan *c)
> +{
> + struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
> + struct stm32_dma_device *dmadev = stm32_dma_chan_get_dev(chan);
> + int ret;
> +
> + chan->config_init = false;
> + ret = clk_prepare_enable(dmadev->clk);
> + if (ret < 0) {
> + dev_err(chan2dev(chan), "clk_prepare_enable failed: %d\n", ret);
> + return ret;
> + }
> +
> + ret = stm32_dma_disable_chan(chan);
> +
> + return ret;
> +}
The error path here looks like it will leak clock references.
> +static int stm32_dma_probe(struct platform_device *pdev)
> +{
> + struct stm32_dma_chan *chan;
> + struct stm32_dma_device *dmadev;
> + struct dma_device *dd;
> + const struct of_device_id *match;
> + unsigned int i;
> + struct resource *res;
> + int ret;
> +
> + match = of_match_device(stm32_dma_of_match, &pdev->dev);
> + if (!match) {
> + dev_err(&pdev->dev, "Error: No device match found\n");
> + return -ENODEV;
> + }
> +
> + dmadev = devm_kzalloc(&pdev->dev, sizeof(*dmadev), GFP_KERNEL);
> + if (!dmadev)
> + return -ENOMEM;
> +
> + dd = &dmadev->ddev;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + dmadev->base = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(dmadev->base))
> + return PTR_ERR(dmadev->base);
> +
> + dmadev->clk = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(dmadev->clk)) {
> + dev_err(&pdev->dev, "Error: Missing controller clock\n");
> + return PTR_ERR(dmadev->clk);
> + }
> +
> + dmadev->mem2mem = of_property_read_bool(pdev->dev.of_node,
> + "st,mem2mem");
> +
> + dmadev->rst = devm_reset_control_get(&pdev->dev, NULL);
> + if (!IS_ERR(dmadev->rst)) {
> + reset_control_assert(dmadev->rst);
> + udelay(2);
> + reset_control_deassert(dmadev->rst);
> + }
> +
> + dma_cap_set(DMA_SLAVE, dd->cap_mask);
> + dma_cap_set(DMA_PRIVATE, dd->cap_mask);
> + dma_cap_set(DMA_CYCLIC, dd->cap_mask);
> + dd->device_alloc_chan_resources = stm32_dma_alloc_chan_resources;
> + dd->device_free_chan_resources = stm32_dma_free_chan_resources;
> + dd->device_tx_status = stm32_dma_tx_status;
> + dd->device_issue_pending = stm32_dma_issue_pending;
> + dd->device_prep_slave_sg = stm32_dma_prep_slave_sg;
> + dd->device_prep_dma_cyclic = stm32_dma_prep_dma_cyclic;
> + dd->device_config = stm32_dma_slave_config;
> + dd->device_terminate_all = stm32_dma_terminate_all;
> + dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
> + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
> + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
> + dd->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
> + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
> + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
> + dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
> + dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
> + dd->dev = &pdev->dev;
> + INIT_LIST_HEAD(&dd->channels);
> +
> + if (dmadev->mem2mem) {
> + dma_cap_set(DMA_MEMCPY, dd->cap_mask);
> + dd->device_prep_dma_memcpy = stm32_dma_prep_dma_memcpy;
> + dd->directions |= BIT(DMA_MEM_TO_MEM);
> + }
> +
> + for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) {
> + chan = &dmadev->chan[i];
> + chan->id = i;
> + chan->vchan.desc_free = stm32_dma_desc_free;
> + vchan_init(&chan->vchan, dd);
> + }
> +
> + ret = dma_async_device_register(dd);
> + if (ret)
> + return ret;
> +
> + for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) {
> + chan = &dmadev->chan[i];
> + res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
> + if (!res) {
> + ret = -EINVAL;
> + dev_err(&pdev->dev, "No irq resource for chan %d\n", i);
> + goto err_unregister;
> + }
> + chan->irq = res->start;
> + ret = devm_request_irq(&pdev->dev, chan->irq,
> + stm32_dma_chan_irq, 0,
> + dev_name(chan2dev(chan)), chan);
> + if (ret) {
> + dev_err(&pdev->dev,
> + "request_irq failed with err %d channel %d\n",
> + ret, i);
> + goto err_unregister;
> + }
> + }
> +
> + ret = of_dma_controller_register(pdev->dev.of_node,
> + stm32_dma_of_xlate, dmadev);
> + if (ret < 0) {
> + dev_err(&pdev->dev,
> + "STM32 DMA DMA OF registration failed %d\n", ret);
> + goto err_unregister;
> + }
> +
> + platform_set_drvdata(pdev, dmadev);
> +
> + dev_info(&pdev->dev, "STM32 DMA driver registered\n");
> +
> + return 0;
> +
> +err_unregister:
> + dma_async_device_unregister(dd);
> +
> + return ret;
> +}
> +
> +static int stm32_dma_remove(struct platform_device *pdev)
> +{
> + struct stm32_dma_device *dmadev = platform_get_drvdata(pdev);
> +
> + of_dma_controller_free(pdev->dev.of_node);
> +
> + dma_async_device_unregister(&dmadev->ddev);
> +
> + clk_disable_unprepare(dmadev->clk);
What is the purpose of disabling/unpreparing the clock here?
stm32_dma_alloc_chan_resources() and stm32_dma_free_chan_resources()
should pair up and the clock should already be stopped.
Daniel.
next prev parent reply other threads:[~2015-10-13 14:34 UTC|newest]
Thread overview: 51+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-10-13 14:05 [PATCH v2 0/4] Add support for STM32 DMA M'boumba Cedric Madianga
2015-10-13 14:05 ` M'boumba Cedric Madianga
2015-10-13 14:05 ` [PATCH v2 1/4] dt-bindings: Document the STM32 DMA bindings M'boumba Cedric Madianga
2015-10-13 14:05 ` M'boumba Cedric Madianga
2015-10-14 8:54 ` M'boumba Cedric Madianga
2015-10-14 8:54 ` M'boumba Cedric Madianga
2015-10-13 14:05 ` [PATCH v2 2/4] dmaengine: Add STM32 DMA driver M'boumba Cedric Madianga
2015-10-13 14:05 ` M'boumba Cedric Madianga
2015-10-13 14:34 ` Daniel Thompson [this message]
2015-10-13 14:34 ` Daniel Thompson
2015-10-13 14:34 ` Daniel Thompson
2015-10-14 7:54 ` M'boumba Cedric Madianga
2015-10-14 7:54 ` M'boumba Cedric Madianga
2015-10-14 7:54 ` M'boumba Cedric Madianga
2015-10-14 8:52 ` Daniel Thompson
2015-10-14 8:52 ` Daniel Thompson
2015-10-14 8:57 ` M'boumba Cedric Madianga
2015-10-14 8:57 ` M'boumba Cedric Madianga
2015-10-14 8:57 ` M'boumba Cedric Madianga
2015-10-14 13:17 ` M'boumba Cedric Madianga
2015-10-14 13:17 ` M'boumba Cedric Madianga
2015-10-14 13:29 ` Daniel Thompson
2015-10-14 13:29 ` Daniel Thompson
2015-10-14 13:29 ` Daniel Thompson
2015-10-14 13:41 ` M'boumba Cedric Madianga
2015-10-14 13:41 ` M'boumba Cedric Madianga
2015-10-14 14:24 ` Daniel Thompson
2015-10-14 14:24 ` Daniel Thompson
2015-10-14 15:26 ` M'boumba Cedric Madianga
2015-10-14 15:26 ` M'boumba Cedric Madianga
2015-10-14 15:26 ` M'boumba Cedric Madianga
2015-10-14 15:28 ` Daniel Thompson
2015-10-14 15:28 ` Daniel Thompson
2015-10-14 15:41 ` M'boumba Cedric Madianga
2015-10-14 15:41 ` M'boumba Cedric Madianga
2015-10-14 15:41 ` M'boumba Cedric Madianga
2015-10-15 4:07 ` Vinod Koul
2015-10-15 4:07 ` Vinod Koul
2015-10-15 4:07 ` Vinod Koul
2015-10-14 11:16 ` Vinod Koul
2015-10-14 11:16 ` Vinod Koul
2015-10-14 11:16 ` Vinod Koul
2015-10-14 13:07 ` M'boumba Cedric Madianga
2015-10-14 13:07 ` M'boumba Cedric Madianga
2015-10-14 14:14 ` Vinod Koul
2015-10-14 14:14 ` Vinod Koul
2015-10-14 14:14 ` Vinod Koul
2015-10-13 14:05 ` [PATCH v2 3/4] ARM: dts: Add STM32 DMA support for STM32F429 MCU M'boumba Cedric Madianga
2015-10-13 14:05 ` M'boumba Cedric Madianga
2015-10-13 14:05 ` [PATCH v2 4/4] ARM: configs: Add STM32 DMA support in STM32 defconfig M'boumba Cedric Madianga
2015-10-13 14:05 ` M'boumba Cedric Madianga
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=561D1689.90703@linaro.org \
--to=daniel.thompson@linaro.org \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.