aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuthikulpanit, Suravee <Suravee.Suthikulpanit@amd.com>2015-06-10 12:08:52 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-06-15 08:40:48 -0400
commitd0562674838c08ff142c0e9a8e12634e133c4361 (patch)
tree969dc352b9de229af3248a5ea11830c1db9eedaf
parentfaacd5ad83857300df4b7b1814ef2eb963063c14 (diff)
ACPI / scan: Parse _CCA and setup device coherency
This patch implements support for ACPI _CCA object, which is introduced in ACPIv5.1, can be used for specifying device DMA coherency attribute. The parsing logic traverses device namespace to parse coherency information, and stores it in acpi_device_flags. Then uses it to call arch_setup_dma_ops() when creating each device enumerated in DSDT during ACPI scan. This patch also introduces acpi_dma_is_coherent(), which provides an interface for device drivers to check the coherency information similarly to the of_dma_is_coherent(). Signed-off-by: Mark Salter <msalter@redhat.com> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/Kconfig3
-rw-r--r--drivers/acpi/acpi_platform.c2
-rw-r--r--drivers/acpi/glue.c5
-rw-r--r--drivers/acpi/scan.c35
-rw-r--r--include/acpi/acpi_bus.h37
-rw-r--r--include/linux/acpi.h5
6 files changed, 85 insertions, 2 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index ab2cbb51c6aa..212735f3f074 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -54,6 +54,9 @@ config ACPI_GENERIC_GSI
54config ACPI_SYSTEM_POWER_STATES_SUPPORT 54config ACPI_SYSTEM_POWER_STATES_SUPPORT
55 bool 55 bool
56 56
57config ACPI_CCA_REQUIRED
58 bool
59
57config ACPI_SLEEP 60config ACPI_SLEEP
58 bool 61 bool
59 depends on SUSPEND || HIBERNATION 62 depends on SUSPEND || HIBERNATION
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index 4bf75597f732..06a67d5f2846 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -103,7 +103,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
103 pdevinfo.res = resources; 103 pdevinfo.res = resources;
104 pdevinfo.num_res = count; 104 pdevinfo.num_res = count;
105 pdevinfo.fwnode = acpi_fwnode_handle(adev); 105 pdevinfo.fwnode = acpi_fwnode_handle(adev);
106 pdevinfo.dma_mask = DMA_BIT_MASK(32); 106 pdevinfo.dma_mask = acpi_check_dma(adev, NULL) ? DMA_BIT_MASK(32) : 0;
107 pdev = platform_device_register_full(&pdevinfo); 107 pdev = platform_device_register_full(&pdevinfo);
108 if (IS_ERR(pdev)) 108 if (IS_ERR(pdev))
109 dev_err(&adev->dev, "platform device creation failed: %ld\n", 109 dev_err(&adev->dev, "platform device creation failed: %ld\n",
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 39c485b0c25c..b9657af751d1 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -13,6 +13,7 @@
13#include <linux/slab.h> 13#include <linux/slab.h>
14#include <linux/rwsem.h> 14#include <linux/rwsem.h>
15#include <linux/acpi.h> 15#include <linux/acpi.h>
16#include <linux/dma-mapping.h>
16 17
17#include "internal.h" 18#include "internal.h"
18 19
@@ -167,6 +168,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
167 struct list_head *physnode_list; 168 struct list_head *physnode_list;
168 unsigned int node_id; 169 unsigned int node_id;
169 int retval = -EINVAL; 170 int retval = -EINVAL;
171 bool coherent;
170 172
171 if (has_acpi_companion(dev)) { 173 if (has_acpi_companion(dev)) {
172 if (acpi_dev) { 174 if (acpi_dev) {
@@ -223,6 +225,9 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
223 if (!has_acpi_companion(dev)) 225 if (!has_acpi_companion(dev))
224 ACPI_COMPANION_SET(dev, acpi_dev); 226 ACPI_COMPANION_SET(dev, acpi_dev);
225 227
228 if (acpi_check_dma(acpi_dev, &coherent))
229 arch_setup_dma_ops(dev, 0, 0, NULL, coherent);
230
226 acpi_physnode_link_name(physical_node_name, node_id); 231 acpi_physnode_link_name(physical_node_name, node_id);
227 retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, 232 retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
228 physical_node_name); 233 physical_node_name);
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 0a099917a006..67509b23172c 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -11,6 +11,7 @@
11#include <linux/kthread.h> 11#include <linux/kthread.h>
12#include <linux/dmi.h> 12#include <linux/dmi.h>
13#include <linux/nls.h> 13#include <linux/nls.h>
14#include <linux/dma-mapping.h>
14 15
15#include <asm/pgtable.h> 16#include <asm/pgtable.h>
16 17
@@ -2111,6 +2112,39 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp)
2111 kfree(pnp->unique_id); 2112 kfree(pnp->unique_id);
2112} 2113}
2113 2114
2115static void acpi_init_coherency(struct acpi_device *adev)
2116{
2117 unsigned long long cca = 0;
2118 acpi_status status;
2119 struct acpi_device *parent = adev->parent;
2120
2121 if (parent && parent->flags.cca_seen) {
2122 /*
2123 * From ACPI spec, OSPM will ignore _CCA if an ancestor
2124 * already saw one.
2125 */
2126 adev->flags.cca_seen = 1;
2127 cca = parent->flags.coherent_dma;
2128 } else {
2129 status = acpi_evaluate_integer(adev->handle, "_CCA",
2130 NULL, &cca);
2131 if (ACPI_SUCCESS(status))
2132 adev->flags.cca_seen = 1;
2133 else if (!IS_ENABLED(CONFIG_ACPI_CCA_REQUIRED))
2134 /*
2135 * If architecture does not specify that _CCA is
2136 * required for DMA-able devices (e.g. x86),
2137 * we default to _CCA=1.
2138 */
2139 cca = 1;
2140 else
2141 acpi_handle_debug(adev->handle,
2142 "ACPI device is missing _CCA.\n");
2143 }
2144
2145 adev->flags.coherent_dma = cca;
2146}
2147
2114void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, 2148void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
2115 int type, unsigned long long sta) 2149 int type, unsigned long long sta)
2116{ 2150{
@@ -2129,6 +2163,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
2129 device->flags.visited = false; 2163 device->flags.visited = false;
2130 device_initialize(&device->dev); 2164 device_initialize(&device->dev);
2131 dev_set_uevent_suppress(&device->dev, true); 2165 dev_set_uevent_suppress(&device->dev, true);
2166 acpi_init_coherency(device);
2132} 2167}
2133 2168
2134void acpi_device_add_finalize(struct acpi_device *device) 2169void acpi_device_add_finalize(struct acpi_device *device)
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index da079976971f..54df54d00cd2 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -209,7 +209,9 @@ struct acpi_device_flags {
209 u32 hotplug_notify:1; 209 u32 hotplug_notify:1;
210 u32 is_dock_station:1; 210 u32 is_dock_station:1;
211 u32 of_compatible_ok:1; 211 u32 of_compatible_ok:1;
212 u32 reserved:22; 212 u32 coherent_dma:1;
213 u32 cca_seen:1;
214 u32 reserved:20;
213}; 215};
214 216
215/* File System */ 217/* File System */
@@ -381,6 +383,39 @@ struct acpi_device {
381 void (*remove)(struct acpi_device *); 383 void (*remove)(struct acpi_device *);
382}; 384};
383 385
386static inline bool acpi_check_dma(struct acpi_device *adev, bool *coherent)
387{
388 bool ret = false;
389
390 if (!adev)
391 return ret;
392
393 /**
394 * Currently, we only support _CCA=1 (i.e. coherent_dma=1)
395 * This should be equivalent to specifyig dma-coherent for
396 * a device in OF.
397 *
398 * For the case when _CCA=0 (i.e. coherent_dma=0 && cca_seen=1),
399 * There are two cases:
400 * case 1. Do not support and disable DMA.
401 * case 2. Support but rely on arch-specific cache maintenance for
402 * non-coherence DMA operations.
403 * Currently, we implement case 1 above.
404 *
405 * For the case when _CCA is missing (i.e. cca_seen=0) and
406 * platform specifies ACPI_CCA_REQUIRED, we do not support DMA,
407 * and fallback to arch-specific default handling.
408 *
409 * See acpi_init_coherency() for more info.
410 */
411 if (adev->flags.coherent_dma) {
412 ret = true;
413 if (coherent)
414 *coherent = adev->flags.coherent_dma;
415 }
416 return ret;
417}
418
384static inline bool is_acpi_node(struct fwnode_handle *fwnode) 419static inline bool is_acpi_node(struct fwnode_handle *fwnode)
385{ 420{
386 return fwnode && fwnode->type == FWNODE_ACPI; 421 return fwnode && fwnode->type == FWNODE_ACPI;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index e4da5e35e29c..d46a48c21c67 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -569,6 +569,11 @@ static inline int acpi_device_modalias(struct device *dev,
569 return -ENODEV; 569 return -ENODEV;
570} 570}
571 571
572static inline bool acpi_check_dma(struct acpi_device *adev, bool *coherent)
573{
574 return false;
575}
576
572#define ACPI_PTR(_ptr) (NULL) 577#define ACPI_PTR(_ptr) (NULL)
573 578
574#endif /* !CONFIG_ACPI */ 579#endif /* !CONFIG_ACPI */