diff mbox

[11/31] dma: add channel request API that supports deferred probe

Message ID 1384548866-13141-12-git-send-email-swarren@wwwdotorg.org (mailing list archive)
State New, archived
Headers show

Commit Message

Stephen Warren Nov. 15, 2013, 8:54 p.m. UTC
From: Stephen Warren <swarren@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@nvidia.com
Cc: pdeschrijver@nvidia.com
Cc: linux-tegra@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Stephen Warren <swarren@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(-)

Comments

Andy Shevchenko Nov. 18, 2013, 9:18 a.m. UTC | #1
On Fri, 2013-11-15 at 13:01 -0800, Dan Williams wrote:
> On Fri, Nov 15, 2013 at 12:54 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:

> > Eventually, all drivers should be converted to this new API, the old API
> > removed, and the new API renamed to the more desirable name. 

I really would like to see more sensible and shorter names for the API
functions.

[]

> > acpi_dma_request_slave_chan_by_index() doesn't actually implement
> > deferred probe. Perhaps it should?

Yes it should, though I propose we will add this a bit later since we
will survive w/o it.

My comments regarding acpi-dma.c below.

[]

> > --- 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,

We use default value of chan if it's not found. Perhaps you have to
change it as well to something like ERR_PTR(-ENOENT).

[]

> > @@ -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);

In this case I would rather use -ENODATA, since it means we have no
FixedDMA descriptor for the device under question.

[]

> >  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);

Perhaps -EINVAL, since it means the input parameter kinda wrong.
Stephen Warren Nov. 18, 2013, 5:42 p.m. UTC | #2
On 11/18/2013 02:18 AM, Shevchenko, Andriy wrote:
> On Fri, 2013-11-15 at 13:01 -0800, Dan Williams wrote:
>> On Fri, Nov 15, 2013 at 12:54 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> 
>>> Eventually, all drivers should be converted to this new API, the old API
>>> removed, and the new API renamed to the more desirable name. 
> 
> I really would like to see more sensible and shorter names for the API
> functions.

I'm not sure if you're suggesting that you:

a) Really want to API renaming I mention above to happen at some time.

b) We need to pick a better name now, for the new API this patch
introduces. If so, do you have any better suggestion?

>>> --- 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,
> 
> We use default value of chan if it's not found. Perhaps you have to
> change it as well to something like ERR_PTR(-ENOENT).

Ah yes. I think I'll keep the default value of chan = NULL, and just
change the return statement to something like:

return chan ? chan : ERR_PTR(-ENOENT);

That way, the fact that adma->acpi_dma_xlate() returns
NULL-or-valid-pointer and the check of chan against NULL inside the
list_for_each_entry() won't have to change.
Andy Shevchenko Nov. 19, 2013, noon UTC | #3
On Mon, 2013-11-18 at 10:42 -0700, Stephen Warren wrote:
> On 11/18/2013 02:18 AM, Shevchenko, Andriy wrote:
> > On Fri, 2013-11-15 at 13:01 -0800, Dan Williams wrote:
> >> On Fri, Nov 15, 2013 at 12:54 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> > 
> >>> Eventually, all drivers should be converted to this new API, the old API
> >>> removed, and the new API renamed to the more desirable name. 
> > 
> > I really would like to see more sensible and shorter names for the API
> > functions.
> 
> I'm not sure if you're suggesting that you:
> 
> a) Really want to API renaming I mention above to happen at some time.
> 
> b) We need to pick a better name now, for the new API this patch
> introduces. If so, do you have any better suggestion?

Sooner better, I think. 

Now only what I can propose is to change
dma_slave_request_channel_or_err() to dma_slave_request_chan().

In any way the dma_slave_request_* API is quite new and we, as far as I
understood, will come when the main request function will always return
channel or error.
Stephen Warren Nov. 19, 2013, 5:15 p.m. UTC | #4
On 11/19/2013 05:00 AM, Andy Shevchenko wrote:
> On Mon, 2013-11-18 at 10:42 -0700, Stephen Warren wrote:
>> On 11/18/2013 02:18 AM, Shevchenko, Andriy wrote:
>>> On Fri, 2013-11-15 at 13:01 -0800, Dan Williams wrote:
>>>> On Fri, Nov 15, 2013 at 12:54 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>>
>>>>> Eventually, all drivers should be converted to this new API, the old API
>>>>> removed, and the new API renamed to the more desirable name. 
>>>
>>> I really would like to see more sensible and shorter names for the API
>>> functions.
>>
>> I'm not sure if you're suggesting that you:
>>
>> a) Really want to API renaming I mention above to happen at some time.
>>
>> b) We need to pick a better name now, for the new API this patch
>> introduces. If so, do you have any better suggestion?
> 
> Sooner better, I think. 
> 
> Now only what I can propose is to change
> dma_slave_request_channel_or_err() to dma_slave_request_chan().

The one downside I see with the name dma_slave_request_chan() is that
it's very similar to the existing dma_request_slave_channel(); driver
authors may well be confused which is which, and end up using the wrong
one. That's why I added an explicit "_or_err" to the function name.
Still, I can go for dma_slave_request_chan() if the dmaengine
maintainers think it's the right choice; just let me know.
Dan Williams Nov. 19, 2013, 11:37 p.m. UTC | #5
On Tue, Nov 19, 2013 at 9:15 AM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 11/19/2013 05:00 AM, Andy Shevchenko wrote:
>> On Mon, 2013-11-18 at 10:42 -0700, Stephen Warren wrote:
>>> On 11/18/2013 02:18 AM, Shevchenko, Andriy wrote:
>>>> On Fri, 2013-11-15 at 13:01 -0800, Dan Williams wrote:
>>>>> On Fri, Nov 15, 2013 at 12:54 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>>>
>>>>>> Eventually, all drivers should be converted to this new API, the old API
>>>>>> removed, and the new API renamed to the more desirable name.
>>>>
>>>> I really would like to see more sensible and shorter names for the API
>>>> functions.
>>>
>>> I'm not sure if you're suggesting that you:
>>>
>>> a) Really want to API renaming I mention above to happen at some time.
>>>
>>> b) We need to pick a better name now, for the new API this patch
>>> introduces. If so, do you have any better suggestion?
>>
>> Sooner better, I think.
>>
>> Now only what I can propose is to change
>> dma_slave_request_channel_or_err() to dma_slave_request_chan().
>
> The one downside I see with the name dma_slave_request_chan() is that
> it's very similar to the existing dma_request_slave_channel(); driver
> authors may well be confused which is which, and end up using the wrong
> one. That's why I added an explicit "_or_err" to the function name.
> Still, I can go for dma_slave_request_chan() if the dmaengine
> maintainers think it's the right choice; just let me know.

I think the problem with dma_slave_request_channel_or_err() is that it
does not tell you what the function does or how it's different from
the existing one.  I think dma_slave_request_channel_defer() with a
comment about what error value callers should be expecting to
delineate a permanent error vs "try again later".
Stephen Warren Nov. 20, 2013, 12:09 a.m. UTC | #6
On 11/19/2013 04:37 PM, Dan Williams wrote:
> On Tue, Nov 19, 2013 at 9:15 AM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 11/19/2013 05:00 AM, Andy Shevchenko wrote:
>>> On Mon, 2013-11-18 at 10:42 -0700, Stephen Warren wrote:
>>>> On 11/18/2013 02:18 AM, Shevchenko, Andriy wrote:
>>>>> On Fri, 2013-11-15 at 13:01 -0800, Dan Williams wrote:
>>>>>> On Fri, Nov 15, 2013 at 12:54 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>>>>
>>>>>>> Eventually, all drivers should be converted to this new API, the old API
>>>>>>> removed, and the new API renamed to the more desirable name.
>>>>>
>>>>> I really would like to see more sensible and shorter names for the API
>>>>> functions.
>>>>
>>>> I'm not sure if you're suggesting that you:
>>>>
>>>> a) Really want to API renaming I mention above to happen at some time.
>>>>
>>>> b) We need to pick a better name now, for the new API this patch
>>>> introduces. If so, do you have any better suggestion?
>>>
>>> Sooner better, I think.
>>>
>>> Now only what I can propose is to change
>>> dma_slave_request_channel_or_err() to dma_slave_request_chan().
>>
>> The one downside I see with the name dma_slave_request_chan() is that
>> it's very similar to the existing dma_request_slave_channel(); driver
>> authors may well be confused which is which, and end up using the wrong
>> one. That's why I added an explicit "_or_err" to the function name.
>> Still, I can go for dma_slave_request_chan() if the dmaengine
>> maintainers think it's the right choice; just let me know.
> 
> I think the problem with dma_slave_request_channel_or_err() is that it
> does not tell you what the function does or how it's different from
> the existing one.  I think dma_slave_request_channel_defer() with a
> comment about what error value callers should be expecting to
> delineate a permanent error vs "try again later".

Deferred probe certainly isn't the only error that can be returned
though, so I don't think "defer" in the name makes much sense. The
function as I wrote it returns a standard "error pointer" value.
Typically, callers would simply propagate *any* error code back to the
caller of probe() without even looking at it; it's the driver core that
checks for -EPROBE_DEFER vs. other error codes. In some cases, drivers
do check in order to avoid printing failure messages in the deferred
probe case, but again that's pretty standard, and not something specific
to this API.
Dan Williams Nov. 20, 2013, 12:38 a.m. UTC | #7
On Tue, Nov 19, 2013 at 4:09 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> Deferred probe certainly isn't the only error that can be returned
> though,

Of course, but do any of those other ones matter?  Certainly not if
they've all been hidden behind a NULL return from
dma_request_slave_channel().

> so I don't think "defer" in the name makes much sense. The
> function as I wrote it returns a standard "error pointer" value.
> Typically, callers would simply propagate *any* error code back to the
> caller of probe() without even looking at it; it's the driver core that
> checks for -EPROBE_DEFER vs. other error codes. In some cases, drivers
> do check in order to avoid printing failure messages in the deferred
> probe case, but again that's pretty standard, and not something specific
> to this API.

Right, but the only reason to introduce this API is to propagate
EPROBE_DEFER, right?  It also serves to document drivers that are
prepared for / depend on deferred probing support.

Good old bike shedding... I only jumped in because I think changing it
to dma_slave_request_chan() would indeed be confusing .
Stephen Warren Nov. 20, 2013, 6:24 p.m. UTC | #8
On 11/19/2013 05:38 PM, Dan Williams wrote:
> On Tue, Nov 19, 2013 at 4:09 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> Deferred probe certainly isn't the only error that can be returned
>> though,
> 
> Of course, but do any of those other ones matter?  Certainly not if
> they've all been hidden behind a NULL return from
> dma_request_slave_channel().
> 
>> so I don't think "defer" in the name makes much sense. The
>> function as I wrote it returns a standard "error pointer" value.
>> Typically, callers would simply propagate *any* error code back to the
>> caller of probe() without even looking at it; it's the driver core that
>> checks for -EPROBE_DEFER vs. other error codes. In some cases, drivers
>> do check in order to avoid printing failure messages in the deferred
>> probe case, but again that's pretty standard, and not something specific
>> to this API.
> 
> Right, but the only reason to introduce this API is to propagate
> EPROBE_DEFER, right?  It also serves to document drivers that are
> prepared for / depend on deferred probing support.

Well, that's the reason I'm introducing the API, but it's not really
what the API actually does.

That said, in the interests of moving this forward, I'll go for your
suggested name dma_slave_request_channel_defer().

Do I need an ack from Vinod on the function name, or the patches?
Dan Williams Nov. 20, 2013, 7:15 p.m. UTC | #9
On Wed, Nov 20, 2013 at 10:24 AM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 11/19/2013 05:38 PM, Dan Williams wrote:
>> On Tue, Nov 19, 2013 at 4:09 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>> Deferred probe certainly isn't the only error that can be returned
>>> though,
>>
>> Of course, but do any of those other ones matter?  Certainly not if
>> they've all been hidden behind a NULL return from
>> dma_request_slave_channel().
>>
>>> so I don't think "defer" in the name makes much sense. The
>>> function as I wrote it returns a standard "error pointer" value.
>>> Typically, callers would simply propagate *any* error code back to the
>>> caller of probe() without even looking at it; it's the driver core that
>>> checks for -EPROBE_DEFER vs. other error codes. In some cases, drivers
>>> do check in order to avoid printing failure messages in the deferred
>>> probe case, but again that's pretty standard, and not something specific
>>> to this API.
>>
>> Right, but the only reason to introduce this API is to propagate
>> EPROBE_DEFER, right?  It also serves to document drivers that are
>> prepared for / depend on deferred probing support.
>
> Well, that's the reason I'm introducing the API, but it's not really
> what the API actually does.
>

True, this is quite a bit of back and forth for something that will be
temporary.  How bad would it be to short-circuit this discussion and
go straight to converting dma_request_slave_channel().  Leave
dma_request_channel() as is and just convert the 20 or so users of
dma_request_slave_channel() over?

Also seems you could drop the changes to acpi-dma.c altogether if we
pass the result through IS_ERR_OR_NULL().

> That said, in the interests of moving this forward, I'll go for your
> suggested name dma_slave_request_channel_defer().
>
> Do I need an ack from Vinod on the function name, or the patches?

Yes, Vinod should ultimately ack all dma-slave patches... and throw in
another name recommendation for good measure ;-).
Stephen Warren Nov. 20, 2013, 7:22 p.m. UTC | #10
On 11/20/2013 12:15 PM, Dan Williams wrote:
> On Wed, Nov 20, 2013 at 10:24 AM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 11/19/2013 05:38 PM, Dan Williams wrote:
>>> On Tue, Nov 19, 2013 at 4:09 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>>> Deferred probe certainly isn't the only error that can be returned
>>>> though,
>>>
>>> Of course, but do any of those other ones matter?  Certainly not if
>>> they've all been hidden behind a NULL return from
>>> dma_request_slave_channel().
>>>
>>>> so I don't think "defer" in the name makes much sense. The
>>>> function as I wrote it returns a standard "error pointer" value.
>>>> Typically, callers would simply propagate *any* error code back to the
>>>> caller of probe() without even looking at it; it's the driver core that
>>>> checks for -EPROBE_DEFER vs. other error codes. In some cases, drivers
>>>> do check in order to avoid printing failure messages in the deferred
>>>> probe case, but again that's pretty standard, and not something specific
>>>> to this API.
>>>
>>> Right, but the only reason to introduce this API is to propagate
>>> EPROBE_DEFER, right?  It also serves to document drivers that are
>>> prepared for / depend on deferred probing support.
>>
>> Well, that's the reason I'm introducing the API, but it's not really
>> what the API actually does.
>>
> 
> True, this is quite a bit of back and forth for something that will be
> temporary.  How bad would it be to short-circuit this discussion and
> go straight to converting dma_request_slave_channel().  Leave
> dma_request_channel() as is and just convert the 20 or so users of
> dma_request_slave_channel() over?

I had thought about that, but there are drivers that use
dma_request_slave_channel(), but fall back to dma_request_channel() if
that fails. I think there were other cases where the two APIs were
mixed. Drivers would then have a value that sometimes IS_ERR() or is
valid, and other times ==NULL or is valid. So, the values would have to
be checked using IS_ERR_OR_NULL() which I believe is now deprecated  -
certainly Russell will shout at me if I start introducing more usage! So
that means converting dma_request_channel()'s return value too, and that
is a /lot/ more to convert. I suppose an alternative might be to have
the individual affected drivers convert a NULL return from
dma_request_channel() to an ERR value, but for some reason I forget now,
even that looked problematic.
Dan Williams Nov. 22, 2013, 11:50 p.m. UTC | #11
A question about the patch:

On Fri, Nov 15, 2013 at 12:54 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> From: Stephen Warren <swarren@nvidia.com>
[..]
> 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
> @@ -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;
>         }

Why do we need to make this conditional on the value of 'defer'?  If
the client cares it will propagate the error if it does not care then
nothing is gained by converting this to -ENODEV.
Stephen Warren Nov. 23, 2013, 12:05 a.m. UTC | #12
On 11/22/2013 04:50 PM, Dan Williams wrote:
> A question about the patch:
> 
> On Fri, Nov 15, 2013 at 12:54 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> From: Stephen Warren <swarren@nvidia.com>
> [..]
>> 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
>> @@ -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;
>>         }
> 
> Why do we need to make this conditional on the value of 'defer'?  If
> the client cares it will propagate the error if it does not care then
> nothing is gained by converting this to -ENODEV.

The function ends up being called from two code-paths. One of which
wants the new behaviour of deferring probe if a valid DMA specifier is
found but there's not registered driver for it, and the other
(compatibility) path wants exactly the old behaviour. The flag is passed
down from dma_request_slave_channel() (old behaviour) or
dma_request_slave_channel_or_err() (new behaviour).
diff mbox

Patch

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;
 }