diff mbox

[V3,2/4] ACPI/scan: Clean up acpi_check_dma

Message ID 1440597279-11802-3-git-send-email-Suravee.Suthikulpanit@amd.com
State Not Applicable
Headers show

Commit Message

Suravee Suthikulpanit Aug. 26, 2015, 1:54 p.m. UTC
The original name of acpi_check_dma() function does not clearly tell what
exactly it is checking. Also, returning two boolean values (one to indicate
device is DMA capability, and the other to inidicate device coherency
attribute) can be confusing.

So, in order to simplify the function, this patch renames acpi_check_dma()
to acpi_check_dma_coherency() to clearly indicate the purpose of this
function, and only returns an integer where -1 means DMA not supported,
1 means coherent DMA, and 0 means non-coherent DMA.

Also, this patch moves the function into drivers/acpi/scan.c since
it is easier to follow the logic in the acpi_init_coherency() in the
same file here.

Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
Suggested-by: Bjorn Helgaas <bhelgaas@google.com>
Suggested-by: Rafael J. Wysocki <rjw@rjwysocki.net>
CC: Catalin Marinas <catalin.marinas@arm.com>
CC: Rob Herring <robh+dt@kernel.org>
CC: Will Deacon <will.deacon@arm.com>
---
 drivers/acpi/acpi_platform.c |  7 ++++++-
 drivers/acpi/glue.c          |  6 +++---
 drivers/acpi/scan.c          | 39 +++++++++++++++++++++++++++++++++++++++
 drivers/base/property.c      | 10 +++++++---
 include/acpi/acpi_bus.h      | 36 ++----------------------------------
 include/linux/acpi.h         |  4 ++--
 6 files changed, 59 insertions(+), 43 deletions(-)

Comments

Bjorn Helgaas Sept. 14, 2015, 4:34 p.m. UTC | #1
On Wed, Aug 26, 2015 at 08:54:37PM +0700, Suravee Suthikulpanit wrote:
> The original name of acpi_check_dma() function does not clearly tell what
> exactly it is checking. Also, returning two boolean values (one to indicate
> device is DMA capability, and the other to inidicate device coherency

s/inidicate/indicate/

> attribute) can be confusing.
> 
> So, in order to simplify the function, this patch renames acpi_check_dma()
> to acpi_check_dma_coherency() to clearly indicate the purpose of this
> function, and only returns an integer where -1 means DMA not supported,
> 1 means coherent DMA, and 0 means non-coherent DMA.

I think acpi_check_dma_coherency() is better, but only slightly.  It
still doesn't give a hint about the *sense* of the return value.  I
think it'd be easier to read if there were two functions, e.g.,

  int acpi_dma_supported(struct acpi_device *adev)
  {
    if (!adev)
      return 0;

    if (adev->flags.cca_seen)
      return 1;

    /*
     * Per ACPI 6.0 sec 6.2.17, assume devices can do cache-coherent
     * DMA on "Intel platforms".  Presumably that includes all x86 and
     * ia64, and other arches will set CONFIG_ACPI_CCA_REQUIRED=y.
     */
    if (!IS_ENABLED(CONFIG_ACPI_CCA_REQUIRED))
      return 1;

    return 0;
  }

  int acpi_dma_is_coherent(struct acpi_device *adev)
  {
    if (!acpi_dma_supported(adev))
      return 0;

    return adev->flags.coherent_dma;
  }

  struct platform_device *acpi_create_platform_device(...)
  {
    ...
    if (acpi_dma_supported(adev))
      pdevinfo.dma_mask = DMA_BIT_MASK(32);

  int acpi_bind_one(...)
  {
    ...
    if (acpi_dma_supported(acpi_dev))
      arch_setup_dma_ops(dev, 0, 0, NULL, retval);

  bool device_dma_is_coherent(...)
  {
    ...
    return acpi_dma_is_coherent(ACPI_COMPANION(dev)):

> Also, this patch moves the function into drivers/acpi/scan.c since
> it is easier to follow the logic in the acpi_init_coherency() in the
> same file here.
> 
> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> Suggested-by: Bjorn Helgaas <bhelgaas@google.com>
> Suggested-by: Rafael J. Wysocki <rjw@rjwysocki.net>
> CC: Catalin Marinas <catalin.marinas@arm.com>
> CC: Rob Herring <robh+dt@kernel.org>
> CC: Will Deacon <will.deacon@arm.com>
> ---
>  drivers/acpi/acpi_platform.c |  7 ++++++-
>  drivers/acpi/glue.c          |  6 +++---
>  drivers/acpi/scan.c          | 39 +++++++++++++++++++++++++++++++++++++++
>  drivers/base/property.c      | 10 +++++++---
>  include/acpi/acpi_bus.h      | 36 ++----------------------------------
>  include/linux/acpi.h         |  4 ++--
>  6 files changed, 59 insertions(+), 43 deletions(-)
> 
> diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
> index 06a67d5..0b17a78 100644
> --- a/drivers/acpi/acpi_platform.c
> +++ b/drivers/acpi/acpi_platform.c
> @@ -103,7 +103,12 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
>  	pdevinfo.res = resources;
>  	pdevinfo.num_res = count;
>  	pdevinfo.fwnode = acpi_fwnode_handle(adev);
> -	pdevinfo.dma_mask = acpi_check_dma(adev, NULL) ? DMA_BIT_MASK(32) : 0;
> +
> +	if (acpi_check_dma_coherency(adev) < 0)
> +		pdevinfo.dma_mask = 0;
> +	else
> +		pdevinfo.dma_mask = DMA_BIT_MASK(32);
> +
>  	pdev = platform_device_register_full(&pdevinfo);
>  	if (IS_ERR(pdev))
>  		dev_err(&adev->dev, "platform device creation failed: %ld\n",
> diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
> index b9657af..9be7f0f 100644
> --- a/drivers/acpi/glue.c
> +++ b/drivers/acpi/glue.c
> @@ -168,7 +168,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
>  	struct list_head *physnode_list;
>  	unsigned int node_id;
>  	int retval = -EINVAL;
> -	bool coherent;
>  
>  	if (has_acpi_companion(dev)) {
>  		if (acpi_dev) {
> @@ -225,8 +224,9 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
>  	if (!has_acpi_companion(dev))
>  		ACPI_COMPANION_SET(dev, acpi_dev);
>  
> -	if (acpi_check_dma(acpi_dev, &coherent))
> -		arch_setup_dma_ops(dev, 0, 0, NULL, coherent);
> +	retval = acpi_check_dma_coherency(acpi_dev);
> +	if (retval >= 0)
> +		arch_setup_dma_ops(dev, 0, 0, NULL, retval);
>  
>  	acpi_physnode_link_name(physical_node_name, node_id);
>  	retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> index ec25635..1d68289 100644
> --- a/drivers/acpi/scan.c
> +++ b/drivers/acpi/scan.c
> @@ -2182,6 +2182,45 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp)
>  	kfree(pnp->unique_id);
>  }
>  
> +/**
> + * acpi_check_dma_coherency - Check DMA coherency for the specified device.
> + * @adev: The pointer to acpi device to check coherency attribute
> + *
> + * Return -ENOTSUPP if DMA is not supported. Otherwise, return 1 if the
> + * device support coherent DMA, or 0 for non-coherent DMA.
> + */
> +int acpi_check_dma_coherency(struct acpi_device *adev)
> +{
> +	int ret = -ENOTSUPP;
> +
> +	if (!adev)
> +		return ret;

There's no need for the local "ret".  You can "return -ENOTSUPP" here and
below, which is easier to read than looking back to see where "ret" was
defined and whether it was modified after being initialized.

> +
> +	/**
> +	 * Currently, we only support _CCA=1 (i.e. coherent_dma=1)
> +	 * This should be equivalent to specifying dma-coherent for
> +	 * a device in OF.
> +	 *
> +	 * For the case when _CCA=0 (i.e. coherent_dma=0 && cca_seen=1),
> +	 * we have two choices:
> +	 *   1. Do not support and disable DMA.

I know you didn't write this comment, but do we actually *disable* DMA in
the sense of turning off PCI bus mastering or calling an ACPI method that
disables DMA by this device?  I suspect we just don't set up DMA ops and
masks for this device.

> +	 *   2. Support but rely on arch-specific cache maintenance for
> +	 *      non-coherenje DMA operations.

s/Support but/Support DMA but/ ?
s/non-coherenje/non-coherent/

> +	 * Currently, we implement case 2 above.
> +	 *
> +	 * For the case when _CCA is missing (i.e. cca_seen=0) and
> +	 * platform specifies ACPI_CCA_REQUIRED, we do not support DMA,
> +	 * and fallback to arch-specific default handling.
> +	 *
> +	 * See acpi_init_coherency() for more info.
> +	 */
> +	if (!adev->flags.cca_seen && IS_ENABLED(CONFIG_ACPI_CCA_REQUIRED))
> +		return ret;
> +
> +	return adev->flags.coherent_dma;
> +}
> +EXPORT_SYMBOL_GPL(acpi_check_dma_coherency);
> +
>  static void acpi_init_coherency(struct acpi_device *adev)
>  {
>  	unsigned long long cca = 0;
> diff --git a/drivers/base/property.c b/drivers/base/property.c
> index f3f6d16..cd45dfc 100644
> --- a/drivers/base/property.c
> +++ b/drivers/base/property.c
> @@ -525,10 +525,14 @@ bool device_dma_is_coherent(struct device *dev)
>  {
>  	bool coherent = false;
>  
> -	if (IS_ENABLED(CONFIG_OF) && dev->of_node)
> +	if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
>  		coherent = of_dma_is_coherent(dev->of_node);
> -	else
> -		acpi_check_dma(ACPI_COMPANION(dev), &coherent);
> +	} else {
> +		int ret = acpi_check_dma_coherency(ACPI_COMPANION(dev));
> +
> +		if (ret >= 0)
> +			coherent = ret;
> +	}
>  
>  	return coherent;
>  }
> diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
> index 7ecb8e4..baf43ea 100644
> --- a/include/acpi/acpi_bus.h
> +++ b/include/acpi/acpi_bus.h
> @@ -382,40 +382,6 @@ struct acpi_device {
>  	void (*remove)(struct acpi_device *);
>  };
>  
> -static inline bool acpi_check_dma(struct acpi_device *adev, bool *coherent)
> -{
> -	bool ret = false;
> -
> -	if (!adev)
> -		return ret;
> -
> -	/**
> -	 * Currently, we only support _CCA=1 (i.e. coherent_dma=1)
> -	 * This should be equivalent to specifyig dma-coherent for
> -	 * a device in OF.
> -	 *
> -	 * For the case when _CCA=0 (i.e. coherent_dma=0 && cca_seen=1),
> -	 * There are two cases:
> -	 * case 1. Do not support and disable DMA.
> -	 * case 2. Support but rely on arch-specific cache maintenance for
> -	 *         non-coherence DMA operations.
> -	 * Currently, we implement case 2 above.
> -	 *
> -	 * For the case when _CCA is missing (i.e. cca_seen=0) and
> -	 * platform specifies ACPI_CCA_REQUIRED, we do not support DMA,
> -	 * and fallback to arch-specific default handling.
> -	 *
> -	 * See acpi_init_coherency() for more info.
> -	 */
> -	if (adev->flags.coherent_dma ||
> -	    (adev->flags.cca_seen && IS_ENABLED(CONFIG_ARM64))) {
> -		ret = true;
> -		if (coherent)
> -			*coherent = adev->flags.coherent_dma;
> -	}
> -	return ret;
> -}
> -
>  static inline bool is_acpi_node(struct fwnode_handle *fwnode)
>  {
>  	return fwnode && fwnode->type == FWNODE_ACPI;
> @@ -640,6 +606,8 @@ static inline bool acpi_device_can_poweroff(struct acpi_device *adev)
>  	return adev->power.states[ACPI_STATE_D3_COLD].flags.valid;
>  }
>  
> +int acpi_check_dma_coherency(struct acpi_device *adev);
> +
>  #else	/* CONFIG_ACPI */
>  
>  static inline int register_acpi_bus_type(void *bus) { return 0; }
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index d2445fa..d350c9e 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -562,9 +562,9 @@ static inline int acpi_device_modalias(struct device *dev,
>  	return -ENODEV;
>  }
>  
> -static inline bool acpi_check_dma(struct acpi_device *adev, bool *coherent)
> +static inline int acpi_check_dma_coherency(struct acpi_device *adev)
>  {
> -	return false;
> +	return -ENOTSUPP;
>  }
>  
>  #define ACPI_PTR(_ptr)	(NULL)
> -- 
> 2.1.0
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Suravee Suthikulpanit Oct. 13, 2015, 3:52 p.m. UTC | #2
Hi Bjorn,

Thanks for your feedback. And sorry for late response. Some how I didn't 
see this earlier.  Please see my comments below.

On 09/14/2015 09:34 AM, Bjorn Helgaas wrote:
>> [..]
>> So, in order to simplify the function, this patch renames acpi_check_dma()
>> to acpi_check_dma_coherency() to clearly indicate the purpose of this
>> function, and only returns an integer where -1 means DMA not supported,
>> 1 means coherent DMA, and 0 means non-coherent DMA.
>
> I think acpi_check_dma_coherency() is better, but only slightly.  It
> still doesn't give a hint about the *sense* of the return value.  I
> think it'd be easier to read if there were two functions, e.g.,

I have been going back-and-forth between the current version, and the 
two-function-approach in the past. I can definitely go with this route 
if you would prefer. Although, if acpi_dma_is_coherent() == 0, it would 
be ambiguous whether DMA is not supported or non-coherent DMA is 
supported. Then, we would need to call acpi_dma_is_supported() to find 
out. So, that's okay with you?

>> [...]
>> +
>> +	/**
>> +	 * Currently, we only support _CCA=1 (i.e. coherent_dma=1)
>> +	 * This should be equivalent to specifying dma-coherent for
>> +	 * a device in OF.
>> +	 *
>> +	 * For the case when _CCA=0 (i.e. coherent_dma=0 && cca_seen=1),
>> +	 * we have two choices:
>> +	 *   1. Do not support and disable DMA.
>
> I know you didn't write this comment, but do we actually *disable* DMA in
> the sense of turning off PCI bus mastering or calling an ACPI method that
> disables DMA by this device?  I suspect we just don't set up DMA ops and
> masks for this device.

Actually, I wrote this comment. When we disable DMA, we basically set 
dma-mask=0 and do not setup DMA ops as you mentioned. We don't actually 
mess with the hardware.

Thanks,
Suravee
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Suravee Suthikulpanit Oct. 13, 2015, 11:53 p.m. UTC | #3
Bjorn / Rafael,

On 10/13/2015 10:52 AM, Suravee Suthikulpanit wrote:
>
> On 09/14/2015 09:34 AM, Bjorn Helgaas wrote:
>> [..]
>> I think acpi_check_dma_coherency() is better, but only slightly.  It
>> still doesn't give a hint about the *sense* of the return value.  I
>> think it'd be easier to read if there were two functions, e.g.,
>
> I have been going back-and-forth between the current version, and the
> two-function-approach in the past. I can definitely go with this route
> if you would prefer. Although, if acpi_dma_is_coherent() == 0, it would
> be ambiguous whether DMA is not supported or non-coherent DMA is
> supported. Then, we would need to call acpi_dma_is_supported() to find
> out. So, that's okay with you?

Thinking about this again, I still think having one API (which can tell 
whether DMA is supported or not, and if so whether it is coherent or 
non-coherent) would be the least confusing and least error prone.

What if we would just have:

     enum dev_dma_type acpi_get_dev_dma_type(struct acpi_device *adev);

where:
     enum dev_dma_type {
         DEV_DMA_NOT_SUPPORTED,
         DEV_DMA_NON_COHERENT,
         DEV_DMA_COHERENT,
     };

This would probably mean that we should modify drivers/base/property.c 
to replace:
     bool device_dma_is_coherent()
to:
     enum dev_dma_type device_get_dma_type()

We used to discuss the enum approach in the past 
(https://lkml.org/lkml/2015/8/25/868). But we only considered at the 
ACPI level at the time. Actually, this should also reflect in the 
property.c.

At this point, only drivers/crypto/ccp/ccp-platform.c and 
drivers/net/ethernet/amd/xgbe/xgbe-main.c are calling the 
device_dma_is_coherent(). So, it should be easy to change this API.

Please let me know your opinions, or if you have other suggestions.

Thanks again,
Suravee

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Bjorn Helgaas Oct. 20, 2015, 2:17 a.m. UTC | #4
On Tue, Oct 13, 2015 at 06:53:28PM -0500, Suravee Suthikulanit wrote:
> Bjorn / Rafael,
> 
> On 10/13/2015 10:52 AM, Suravee Suthikulpanit wrote:
> >
> >On 09/14/2015 09:34 AM, Bjorn Helgaas wrote:
> >>[..]
> >>I think acpi_check_dma_coherency() is better, but only slightly.  It
> >>still doesn't give a hint about the *sense* of the return value.  I
> >>think it'd be easier to read if there were two functions, e.g.,
> >
> >I have been going back-and-forth between the current version, and the
> >two-function-approach in the past. I can definitely go with this route
> >if you would prefer. Although, if acpi_dma_is_coherent() == 0, it would
> >be ambiguous whether DMA is not supported or non-coherent DMA is
> >supported. Then, we would need to call acpi_dma_is_supported() to find
> >out. So, that's okay with you?
> 
> Thinking about this again, I still think having one API (which can
> tell whether DMA is supported or not, and if so whether it is
> coherent or non-coherent) would be the least confusing and least
> error prone.
> 
> What if we would just have:
> 
>     enum dev_dma_type acpi_get_dev_dma_type(struct acpi_device *adev);
> 
> where:
>     enum dev_dma_type {
>         DEV_DMA_NOT_SUPPORTED,
>         DEV_DMA_NON_COHERENT,
>         DEV_DMA_COHERENT,
>     };
> 
> This would probably mean that we should modify
> drivers/base/property.c to replace:
>     bool device_dma_is_coherent()
> to:
>     enum dev_dma_type device_get_dma_type()
> 
> We used to discuss the enum approach in the past
> (https://lkml.org/lkml/2015/8/25/868). But we only considered at the
> ACPI level at the time. Actually, this should also reflect in the
> property.c.
> 
> At this point, only drivers/crypto/ccp/ccp-platform.c and
> drivers/net/ethernet/amd/xgbe/xgbe-main.c are calling the
> device_dma_is_coherent(). So, it should be easy to change this API.

OK, I'm fine with either the enum or Rafael's 0/1/-ENOTSUPP idea.

Bjorn
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Suravee Suthikulpanit Oct. 20, 2015, 12:53 p.m. UTC | #5
Hi Bjorn/Rafael,

Let me redo the patch with enum then. At least, that's more clear to 
everyone.

Thanks,

Suravee

On 10/19/15 21:17, Bjorn Helgaas wrote:
> On Tue, Oct 13, 2015 at 06:53:28PM -0500, Suravee Suthikulanit wrote:
>> Bjorn / Rafael,
>>
>> On 10/13/2015 10:52 AM, Suravee Suthikulpanit wrote:
>>>
>>> On 09/14/2015 09:34 AM, Bjorn Helgaas wrote:
>>>> [..]
>>>> I think acpi_check_dma_coherency() is better, but only slightly.  It
>>>> still doesn't give a hint about the *sense* of the return value.  I
>>>> think it'd be easier to read if there were two functions, e.g.,
>>>
>>> I have been going back-and-forth between the current version, and the
>>> two-function-approach in the past. I can definitely go with this route
>>> if you would prefer. Although, if acpi_dma_is_coherent() == 0, it would
>>> be ambiguous whether DMA is not supported or non-coherent DMA is
>>> supported. Then, we would need to call acpi_dma_is_supported() to find
>>> out. So, that's okay with you?
>>
>> Thinking about this again, I still think having one API (which can
>> tell whether DMA is supported or not, and if so whether it is
>> coherent or non-coherent) would be the least confusing and least
>> error prone.
>>
>> What if we would just have:
>>
>>      enum dev_dma_type acpi_get_dev_dma_type(struct acpi_device *adev);
>>
>> where:
>>      enum dev_dma_type {
>>          DEV_DMA_NOT_SUPPORTED,
>>          DEV_DMA_NON_COHERENT,
>>          DEV_DMA_COHERENT,
>>      };
>>
>> This would probably mean that we should modify
>> drivers/base/property.c to replace:
>>      bool device_dma_is_coherent()
>> to:
>>      enum dev_dma_type device_get_dma_type()
>>
>> We used to discuss the enum approach in the past
>> (https://lkml.org/lkml/2015/8/25/868). But we only considered at the
>> ACPI level at the time. Actually, this should also reflect in the
>> property.c.
>>
>> At this point, only drivers/crypto/ccp/ccp-platform.c and
>> drivers/net/ethernet/amd/xgbe/xgbe-main.c are calling the
>> device_dma_is_coherent(). So, it should be easy to change this API.
>
> OK, I'm fine with either the enum or Rafael's 0/1/-ENOTSUPP idea.
>
> Bjorn
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index 06a67d5..0b17a78 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -103,7 +103,12 @@  struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
 	pdevinfo.res = resources;
 	pdevinfo.num_res = count;
 	pdevinfo.fwnode = acpi_fwnode_handle(adev);
-	pdevinfo.dma_mask = acpi_check_dma(adev, NULL) ? DMA_BIT_MASK(32) : 0;
+
+	if (acpi_check_dma_coherency(adev) < 0)
+		pdevinfo.dma_mask = 0;
+	else
+		pdevinfo.dma_mask = DMA_BIT_MASK(32);
+
 	pdev = platform_device_register_full(&pdevinfo);
 	if (IS_ERR(pdev))
 		dev_err(&adev->dev, "platform device creation failed: %ld\n",
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index b9657af..9be7f0f 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -168,7 +168,6 @@  int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
 	struct list_head *physnode_list;
 	unsigned int node_id;
 	int retval = -EINVAL;
-	bool coherent;
 
 	if (has_acpi_companion(dev)) {
 		if (acpi_dev) {
@@ -225,8 +224,9 @@  int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
 	if (!has_acpi_companion(dev))
 		ACPI_COMPANION_SET(dev, acpi_dev);
 
-	if (acpi_check_dma(acpi_dev, &coherent))
-		arch_setup_dma_ops(dev, 0, 0, NULL, coherent);
+	retval = acpi_check_dma_coherency(acpi_dev);
+	if (retval >= 0)
+		arch_setup_dma_ops(dev, 0, 0, NULL, retval);
 
 	acpi_physnode_link_name(physical_node_name, node_id);
 	retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index ec25635..1d68289 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2182,6 +2182,45 @@  void acpi_free_pnp_ids(struct acpi_device_pnp *pnp)
 	kfree(pnp->unique_id);
 }
 
+/**
+ * acpi_check_dma_coherency - Check DMA coherency for the specified device.
+ * @adev: The pointer to acpi device to check coherency attribute
+ *
+ * Return -ENOTSUPP if DMA is not supported. Otherwise, return 1 if the
+ * device support coherent DMA, or 0 for non-coherent DMA.
+ */
+int acpi_check_dma_coherency(struct acpi_device *adev)
+{
+	int ret = -ENOTSUPP;
+
+	if (!adev)
+		return ret;
+
+	/**
+	 * Currently, we only support _CCA=1 (i.e. coherent_dma=1)
+	 * This should be equivalent to specifying dma-coherent for
+	 * a device in OF.
+	 *
+	 * For the case when _CCA=0 (i.e. coherent_dma=0 && cca_seen=1),
+	 * we have two choices:
+	 *   1. Do not support and disable DMA.
+	 *   2. Support but rely on arch-specific cache maintenance for
+	 *      non-coherenje DMA operations.
+	 * Currently, we implement case 2 above.
+	 *
+	 * For the case when _CCA is missing (i.e. cca_seen=0) and
+	 * platform specifies ACPI_CCA_REQUIRED, we do not support DMA,
+	 * and fallback to arch-specific default handling.
+	 *
+	 * See acpi_init_coherency() for more info.
+	 */
+	if (!adev->flags.cca_seen && IS_ENABLED(CONFIG_ACPI_CCA_REQUIRED))
+		return ret;
+
+	return adev->flags.coherent_dma;
+}
+EXPORT_SYMBOL_GPL(acpi_check_dma_coherency);
+
 static void acpi_init_coherency(struct acpi_device *adev)
 {
 	unsigned long long cca = 0;
diff --git a/drivers/base/property.c b/drivers/base/property.c
index f3f6d16..cd45dfc 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -525,10 +525,14 @@  bool device_dma_is_coherent(struct device *dev)
 {
 	bool coherent = false;
 
-	if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+	if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
 		coherent = of_dma_is_coherent(dev->of_node);
-	else
-		acpi_check_dma(ACPI_COMPANION(dev), &coherent);
+	} else {
+		int ret = acpi_check_dma_coherency(ACPI_COMPANION(dev));
+
+		if (ret >= 0)
+			coherent = ret;
+	}
 
 	return coherent;
 }
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 7ecb8e4..baf43ea 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -382,40 +382,6 @@  struct acpi_device {
 	void (*remove)(struct acpi_device *);
 };
 
-static inline bool acpi_check_dma(struct acpi_device *adev, bool *coherent)
-{
-	bool ret = false;
-
-	if (!adev)
-		return ret;
-
-	/**
-	 * Currently, we only support _CCA=1 (i.e. coherent_dma=1)
-	 * This should be equivalent to specifyig dma-coherent for
-	 * a device in OF.
-	 *
-	 * For the case when _CCA=0 (i.e. coherent_dma=0 && cca_seen=1),
-	 * There are two cases:
-	 * case 1. Do not support and disable DMA.
-	 * case 2. Support but rely on arch-specific cache maintenance for
-	 *         non-coherence DMA operations.
-	 * Currently, we implement case 2 above.
-	 *
-	 * For the case when _CCA is missing (i.e. cca_seen=0) and
-	 * platform specifies ACPI_CCA_REQUIRED, we do not support DMA,
-	 * and fallback to arch-specific default handling.
-	 *
-	 * See acpi_init_coherency() for more info.
-	 */
-	if (adev->flags.coherent_dma ||
-	    (adev->flags.cca_seen && IS_ENABLED(CONFIG_ARM64))) {
-		ret = true;
-		if (coherent)
-			*coherent = adev->flags.coherent_dma;
-	}
-	return ret;
-}
-
 static inline bool is_acpi_node(struct fwnode_handle *fwnode)
 {
 	return fwnode && fwnode->type == FWNODE_ACPI;
@@ -640,6 +606,8 @@  static inline bool acpi_device_can_poweroff(struct acpi_device *adev)
 	return adev->power.states[ACPI_STATE_D3_COLD].flags.valid;
 }
 
+int acpi_check_dma_coherency(struct acpi_device *adev);
+
 #else	/* CONFIG_ACPI */
 
 static inline int register_acpi_bus_type(void *bus) { return 0; }
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index d2445fa..d350c9e 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -562,9 +562,9 @@  static inline int acpi_device_modalias(struct device *dev,
 	return -ENODEV;
 }
 
-static inline bool acpi_check_dma(struct acpi_device *adev, bool *coherent)
+static inline int acpi_check_dma_coherency(struct acpi_device *adev)
 {
-	return false;
+	return -ENOTSUPP;
 }
 
 #define ACPI_PTR(_ptr)	(NULL)