[PATCH 11/31] dma: add channel request API that supports deferred probe
Dan Williams
dan.j.williams at intel.com
Fri Nov 15 16:01:21 EST 2013
[ adding dmaengine list and Vinod ]
On Fri, Nov 15, 2013 at 12:54 PM, Stephen Warren <swarren at wwwdotorg.org> wrote:
> From: Stephen Warren <swarren at nvidia.com>
>
> dma_request_slave_channel() simply returns NULL whenever DMA channel
> lookup fails. Lookup could fail for two distinct reasons:
>
> a) No DMA specification exists for the channel name.
> This includes situations where no DMA specifications exist at all, or
> other general lookup problems.
>
> b) A DMA specification does exist, yet the driver for that channel is not
> yet registered.
>
> Case (b) should trigger deferred probe in client drivers. However, since
> they have no way to differentiate the two situations, it cannot.
>
> Implement new function dma_request_slave_channel_or_err(), which performs
> identically to dma_request_slave_channel(), except that it returns an
> error-pointer rather than NULL, which allows callers to detect when
> deferred probe should occur.
>
> Eventually, all drivers should be converted to this new API, the old API
> removed, and the new API renamed to the more desirable name. This patch
> doesn't convert the existing API and all drivers in one go, since some
> drivers call dma_request_slave_channel() then dma_request_channel() if
> that fails. That would require modifying dma_request_channel() in the
> same way, which would then require modifying close to 100 drivers at once,
> rather than just the 15-20 or so that use dma_request_slave_channel(),
> which might be tenable in a single patch.
>
> acpi_dma_request_slave_chan_by_index() doesn't actually implement
> deferred probe. Perhaps it should?
>
> Cc: treding at nvidia.com
> Cc: pdeschrijver at nvidia.com
> Cc: linux-tegra at vger.kernel.org
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: Dan Williams <dan.j.williams at intel.com>
> Signed-off-by: Stephen Warren <swarren at nvidia.com>
> ---
> This patch is part of a series with strong internal depdendencies. I'm
> looking for an ack so that I can take the entire series through the Tegra
> and arm-soc trees. The series will be part of a stable branch that can be
> merged into other subsystems if needed to avoid/resolve dependencies.
> ---
> drivers/dma/acpi-dma.c | 12 ++++++------
> drivers/dma/dmaengine.c | 44 ++++++++++++++++++++++++++++++++++++++++----
> drivers/dma/of-dma.c | 12 +++++++-----
> include/linux/dmaengine.h | 7 +++++++
> include/linux/of_dma.h | 9 ++++++---
> 5 files changed, 66 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c
> index e69b03c0fa50..c83d40f14467 100644
> --- a/drivers/dma/acpi-dma.c
> +++ b/drivers/dma/acpi-dma.c
> @@ -334,7 +334,7 @@ static int acpi_dma_parse_fixed_dma(struct acpi_resource *res, void *data)
> * @dev: struct device to get DMA request from
> * @index: index of FixedDMA descriptor for @dev
> *
> - * Returns pointer to appropriate dma channel on success or NULL on error.
> + * Returns pointer to appropriate dma channel on success or an error pointer.
> */
> struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
> size_t index)
> @@ -349,10 +349,10 @@ struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
>
> /* Check if the device was enumerated by ACPI */
> if (!dev || !ACPI_HANDLE(dev))
> - return NULL;
> + return ERR_PTR(-ENODEV);
>
> if (acpi_bus_get_device(ACPI_HANDLE(dev), &adev))
> - return NULL;
> + return ERR_PTR(-ENODEV);
>
> memset(&pdata, 0, sizeof(pdata));
> pdata.index = index;
> @@ -367,7 +367,7 @@ struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
> acpi_dev_free_resource_list(&resource_list);
>
> if (dma_spec->slave_id < 0 || dma_spec->chan_id < 0)
> - return NULL;
> + return ERR_PTR(-ENODEV);
>
> mutex_lock(&acpi_dma_lock);
>
> @@ -403,7 +403,7 @@ EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_index);
> * translate the names "tx" and "rx" here based on the most common case where
> * the first FixedDMA descriptor is TX and second is RX.
> *
> - * Returns pointer to appropriate dma channel on success or NULL on error.
> + * Returns pointer to appropriate dma channel on success or an error pointer.
> */
> struct dma_chan *acpi_dma_request_slave_chan_by_name(struct device *dev,
> const char *name)
> @@ -415,7 +415,7 @@ struct dma_chan *acpi_dma_request_slave_chan_by_name(struct device *dev,
> else if (!strcmp(name, "rx"))
> index = 1;
> else
> - return NULL;
> + return ERR_PTR(-ENODEV);
>
> return acpi_dma_request_slave_chan_by_index(dev, index);
> }
> diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
> index ea806bdc12ef..5e7f8af2f0ec 100644
> --- a/drivers/dma/dmaengine.c
> +++ b/drivers/dma/dmaengine.c
> @@ -540,6 +540,8 @@ EXPORT_SYMBOL_GPL(dma_get_slave_channel);
> * @mask: capabilities that the channel must satisfy
> * @fn: optional callback to disposition available channels
> * @fn_param: opaque parameter to pass to dma_filter_fn
> + *
> + * Returns pointer to appropriate dma channel on success or NULL.
> */
> struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
> dma_filter_fn fn, void *fn_param)
> @@ -588,24 +590,58 @@ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
> EXPORT_SYMBOL_GPL(__dma_request_channel);
>
> /**
> - * dma_request_slave_channel - try to allocate an exclusive slave channel
> + * __dma_request_slave_channel - try to allocate an exclusive slave
> + * channel
> * @dev: pointer to client device structure
> * @name: slave channel name
> + *
> + * Returns pointer to appropriate dma channel on success or an error pointer.
> */
> -struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name)
> +static struct dma_chan *__dma_request_slave_channel(struct device *dev,
> + const char *name, bool defer)
> {
> /* If device-tree is present get slave info from here */
> if (dev->of_node)
> - return of_dma_request_slave_channel(dev->of_node, name);
> + return of_dma_request_slave_channel(dev->of_node, name, defer);
>
> /* If device was enumerated by ACPI get slave info from here */
> if (ACPI_HANDLE(dev))
> return acpi_dma_request_slave_chan_by_name(dev, name);
>
> - return NULL;
> + return ERR_PTR(-ENODEV);
> +}
> +
> +/**
> + * dma_request_slave_channel - try to allocate an exclusive slave channel
> + * @dev: pointer to client device structure
> + * @name: slave channel name
> + *
> + * Returns pointer to appropriate dma channel on success or NULL.
> + */
> +struct dma_chan *dma_request_slave_channel(struct device *dev,
> + const char *name)
> +{
> + struct dma_chan *ch = __dma_request_slave_channel(dev, name, false);
> + if (IS_ERR(ch))
> + return NULL;
> + return ch;
> }
> EXPORT_SYMBOL_GPL(dma_request_slave_channel);
>
> +/**
> + * dma_request_slave_channel_or_err - try to allocate an exclusive slave channel
> + * @dev: pointer to client device structure
> + * @name: slave channel name
> + *
> + * Returns pointer to appropriate dma channel on success or an error pointer.
> + */
> +struct dma_chan *dma_request_slave_channel_or_err(struct device *dev,
> + const char *name)
> +{
> + return __dma_request_slave_channel(dev, name, true);
> +}
> +EXPORT_SYMBOL_GPL(dma_request_slave_channel_or_err);
> +
> void dma_release_channel(struct dma_chan *chan)
> {
> mutex_lock(&dma_list_mutex);
> diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c
> index 0b88dd3d05f4..928141f6f21b 100644
> --- a/drivers/dma/of-dma.c
> +++ b/drivers/dma/of-dma.c
> @@ -143,10 +143,10 @@ static int of_dma_match_channel(struct device_node *np, const char *name,
> * @np: device node to get DMA request from
> * @name: name of desired channel
> *
> - * Returns pointer to appropriate dma channel on success or NULL on error.
> + * Returns pointer to appropriate dma channel on success or an error pointer.
> */
> struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
> - const char *name)
> + const char *name, bool defer)
> {
> struct of_phandle_args dma_spec;
> struct of_dma *ofdma;
> @@ -155,14 +155,14 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
>
> if (!np || !name) {
> pr_err("%s: not enough information provided\n", __func__);
> - return NULL;
> + return ERR_PTR(-ENODEV);
> }
>
> count = of_property_count_strings(np, "dma-names");
> if (count < 0) {
> pr_err("%s: dma-names property of node '%s' missing or empty\n",
> __func__, np->full_name);
> - return NULL;
> + return ERR_PTR(-ENODEV);
> }
>
> for (i = 0; i < count; i++) {
> @@ -181,11 +181,13 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
>
> of_node_put(dma_spec.np);
>
> + if (!ofdma && defer)
> + return ERR_PTR(-EPROBE_DEFER);
> if (chan)
> return chan;
> }
>
> - return NULL;
> + return ERR_PTR(-ENODEV);
> }
>
> /**
> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> index 41cf0c399288..b908b0fda72b 100644
> --- a/include/linux/dmaengine.h
> +++ b/include/linux/dmaengine.h
> @@ -1041,6 +1041,8 @@ void dma_issue_pending_all(void);
> struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
> dma_filter_fn fn, void *fn_param);
> struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name);
> +struct dma_chan *dma_request_slave_channel_or_err(struct device *dev,
> + const char *name);
> void dma_release_channel(struct dma_chan *chan);
> #else
> static inline struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type)
> @@ -1068,6 +1070,11 @@ static inline struct dma_chan *dma_request_slave_channel(struct device *dev,
> {
> return NULL;
> }
> +static inline struct dma_chan *dma_request_slave_channel_or_err(
> + struct device *dev, const char *name)
> +{
> + return ERR_PTR(-ENODEV);
> +}
> static inline void dma_release_channel(struct dma_chan *chan)
> {
> }
> diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h
> index ae36298ba076..0504461574c6 100644
> --- a/include/linux/of_dma.h
> +++ b/include/linux/of_dma.h
> @@ -38,7 +38,8 @@ extern int of_dma_controller_register(struct device_node *np,
> void *data);
> extern void of_dma_controller_free(struct device_node *np);
> extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
> - const char *name);
> + const char *name,
> + bool defer);
> extern struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
> struct of_dma *ofdma);
> #else
> @@ -54,8 +55,10 @@ static inline void of_dma_controller_free(struct device_node *np)
> {
> }
>
> -static inline struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
> - const char *name)
> +static inline struct dma_chan *of_dma_request_slave_channel(
> + struct device_node *np,
> + const char *name,
> + bool defer)
> {
> return NULL;
> }
> --
> 1.8.1.5
>
More information about the linux-arm-kernel
mailing list