aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>2013-04-09 07:05:43 -0400
committerVinod Koul <vinod.koul@intel.com>2013-04-15 12:34:10 -0400
commit1b2e98bc1e35ebe1f65c3db62c8317096ad7f2c8 (patch)
tree326e1f7e6f311f1107f27eb048d521e880944360
parenteceec44ecd7f3285468a684e7216df2316b178f3 (diff)
dma: acpi-dma: introduce ACPI DMA helpers
There is a new generic API to get a DMA channel for a slave device (commit 9a6cecc8 "dmaengine: add helper function to request a slave DMA channel"). In similar fashion to the DT case (commit aa3da644 "of: Add generic device tree DMA helpers") we introduce helpers to the DMAC drivers which are enumerated by ACPI. The proposed extension provides the following API calls: acpi_dma_controller_register(), devm_acpi_dma_controller_register() acpi_dma_controller_free(), devm_acpi_dma_controller_free() acpi_dma_simple_xlate() acpi_dma_request_slave_chan_by_index() acpi_dma_request_slave_chan_by_name() The first two should be used, for example, at probe() and remove() of the corresponding DMAC driver. At the register stage the DMAC driver supplies a custom xlate() function to translate a struct dma_spec into struct dma_chan. Accordingly to the ACPI Fixed DMA resource specification the only two pieces of information the slave device has are the channel id and the request line (slave id). Those two are represented by struct dma_spec. The acpi_dma_request_slave_chan_by_index() provides access to the specifix FixedDMA resource by its index. Whereas dma_request_slave_channel() takes a string parameter to identify the DMA resources required by the slave device. To make a slave device driver work with both DeviceTree and ACPI enumeration a simple convention is established: "tx" corresponds to the index 0 and "rx" to the index 1. In case of robust configuration the slave device driver unfortunately needs to call acpi_dma_request_slave_chan_by_index() directly. Additionally the patch provides "managed" version of the register/free pair i.e. devm_acpi_dma_controller_register() and devm_acpi_dma_controller_free(). Usually, the driver uses only devm_acpi_dma_controller_register(). Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r--Documentation/acpi/enumeration.txt77
-rw-r--r--drivers/dma/Kconfig4
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/acpi-dma.c279
-rw-r--r--include/linux/acpi_dma.h116
5 files changed, 477 insertions, 0 deletions
diff --git a/Documentation/acpi/enumeration.txt b/Documentation/acpi/enumeration.txt
index 94a656131885..2874c904f3ef 100644
--- a/Documentation/acpi/enumeration.txt
+++ b/Documentation/acpi/enumeration.txt
@@ -66,6 +66,83 @@ the ACPI device explicitly to acpi_platform_device_ids list defined in
66drivers/acpi/acpi_platform.c. This limitation is only for the platform 66drivers/acpi/acpi_platform.c. This limitation is only for the platform
67devices, SPI and I2C devices are created automatically as described below. 67devices, SPI and I2C devices are created automatically as described below.
68 68
69DMA support
70~~~~~~~~~~~
71DMA controllers enumerated via ACPI should be registered in the system to
72provide generic access to their resources. For example, a driver that would
73like to be accessible to slave devices via generic API call
74dma_request_slave_channel() must register itself at the end of the probe
75function like this:
76
77 err = devm_acpi_dma_controller_register(dev, xlate_func, dw);
78 /* Handle the error if it's not a case of !CONFIG_ACPI */
79
80and implement custom xlate function if needed (usually acpi_dma_simple_xlate()
81is enough) which converts the FixedDMA resource provided by struct
82acpi_dma_spec into the corresponding DMA channel. A piece of code for that case
83could look like:
84
85 #ifdef CONFIG_ACPI
86 struct filter_args {
87 /* Provide necessary information for the filter_func */
88 ...
89 };
90
91 static bool filter_func(struct dma_chan *chan, void *param)
92 {
93 /* Choose the proper channel */
94 ...
95 }
96
97 static struct dma_chan *xlate_func(struct acpi_dma_spec *dma_spec,
98 struct acpi_dma *adma)
99 {
100 dma_cap_mask_t cap;
101 struct filter_args args;
102
103 /* Prepare arguments for filter_func */
104 ...
105 return dma_request_channel(cap, filter_func, &args);
106 }
107 #else
108 static struct dma_chan *xlate_func(struct acpi_dma_spec *dma_spec,
109 struct acpi_dma *adma)
110 {
111 return NULL;
112 }
113 #endif
114
115dma_request_slave_channel() will call xlate_func() for each registered DMA
116controller. In the xlate function the proper channel must be chosen based on
117information in struct acpi_dma_spec and the properties of the controller
118provided by struct acpi_dma.
119
120Clients must call dma_request_slave_channel() with the string parameter that
121corresponds to a specific FixedDMA resource. By default "tx" means the first
122entry of the FixedDMA resource array, "rx" means the second entry. The table
123below shows a layout:
124
125 Device (I2C0)
126 {
127 ...
128 Method (_CRS, 0, NotSerialized)
129 {
130 Name (DBUF, ResourceTemplate ()
131 {
132 FixedDMA (0x0018, 0x0004, Width32bit, _Y48)
133 FixedDMA (0x0019, 0x0005, Width32bit, )
134 })
135 ...
136 }
137 }
138
139So, the FixedDMA with request line 0x0018 is "tx" and next one is "rx" in
140this example.
141
142In robust cases the client unfortunately needs to call
143acpi_dma_request_slave_chan_by_index() directly and therefore choose the
144specific FixedDMA resource by its index.
145
69SPI serial bus support 146SPI serial bus support
70~~~~~~~~~~~~~~~~~~~~~~ 147~~~~~~~~~~~~~~~~~~~~~~
71Slave devices behind SPI bus have SpiSerialBus resource attached to them. 148Slave devices behind SPI bus have SpiSerialBus resource attached to them.
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index d5c58e839b27..afe5b1958382 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -326,6 +326,10 @@ config DMA_ENGINE
326config DMA_VIRTUAL_CHANNELS 326config DMA_VIRTUAL_CHANNELS
327 tristate 327 tristate
328 328
329config DMA_ACPI
330 def_bool y
331 depends on ACPI
332
329config DMA_OF 333config DMA_OF
330 def_bool y 334 def_bool y
331 depends on OF 335 depends on OF
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 488e3ff85b52..268e62634bca 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -3,6 +3,7 @@ ccflags-$(CONFIG_DMADEVICES_VDEBUG) += -DVERBOSE_DEBUG
3 3
4obj-$(CONFIG_DMA_ENGINE) += dmaengine.o 4obj-$(CONFIG_DMA_ENGINE) += dmaengine.o
5obj-$(CONFIG_DMA_VIRTUAL_CHANNELS) += virt-dma.o 5obj-$(CONFIG_DMA_VIRTUAL_CHANNELS) += virt-dma.o
6obj-$(CONFIG_DMA_ACPI) += acpi-dma.o
6obj-$(CONFIG_DMA_OF) += of-dma.o 7obj-$(CONFIG_DMA_OF) += of-dma.o
7 8
8obj-$(CONFIG_NET_DMA) += iovlock.o 9obj-$(CONFIG_NET_DMA) += iovlock.o
diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c
new file mode 100644
index 000000000000..ba6fc62e9651
--- /dev/null
+++ b/drivers/dma/acpi-dma.c
@@ -0,0 +1,279 @@
1/*
2 * ACPI helpers for DMA request / controller
3 *
4 * Based on of-dma.c
5 *
6 * Copyright (C) 2013, Intel Corporation
7 * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/device.h>
15#include <linux/module.h>
16#include <linux/list.h>
17#include <linux/mutex.h>
18#include <linux/slab.h>
19#include <linux/acpi.h>
20#include <linux/acpi_dma.h>
21
22static LIST_HEAD(acpi_dma_list);
23static DEFINE_MUTEX(acpi_dma_lock);
24
25/**
26 * acpi_dma_controller_register - Register a DMA controller to ACPI DMA helpers
27 * @dev: struct device of DMA controller
28 * @acpi_dma_xlate: translation function which converts a dma specifier
29 * into a dma_chan structure
30 * @data pointer to controller specific data to be used by
31 * translation function
32 *
33 * Returns 0 on success or appropriate errno value on error.
34 *
35 * Allocated memory should be freed with appropriate acpi_dma_controller_free()
36 * call.
37 */
38int acpi_dma_controller_register(struct device *dev,
39 struct dma_chan *(*acpi_dma_xlate)
40 (struct acpi_dma_spec *, struct acpi_dma *),
41 void *data)
42{
43 struct acpi_device *adev;
44 struct acpi_dma *adma;
45
46 if (!dev || !acpi_dma_xlate)
47 return -EINVAL;
48
49 /* Check if the device was enumerated by ACPI */
50 if (!ACPI_HANDLE(dev))
51 return -EINVAL;
52
53 if (acpi_bus_get_device(ACPI_HANDLE(dev), &adev))
54 return -EINVAL;
55
56 adma = kzalloc(sizeof(*adma), GFP_KERNEL);
57 if (!adma)
58 return -ENOMEM;
59
60 adma->dev = dev;
61 adma->acpi_dma_xlate = acpi_dma_xlate;
62 adma->data = data;
63
64 /* Now queue acpi_dma controller structure in list */
65 mutex_lock(&acpi_dma_lock);
66 list_add_tail(&adma->dma_controllers, &acpi_dma_list);
67 mutex_unlock(&acpi_dma_lock);
68
69 return 0;
70}
71EXPORT_SYMBOL_GPL(acpi_dma_controller_register);
72
73/**
74 * acpi_dma_controller_free - Remove a DMA controller from ACPI DMA helpers list
75 * @dev: struct device of DMA controller
76 *
77 * Memory allocated by acpi_dma_controller_register() is freed here.
78 */
79int acpi_dma_controller_free(struct device *dev)
80{
81 struct acpi_dma *adma;
82
83 if (!dev)
84 return -EINVAL;
85
86 mutex_lock(&acpi_dma_lock);
87
88 list_for_each_entry(adma, &acpi_dma_list, dma_controllers)
89 if (adma->dev == dev) {
90 list_del(&adma->dma_controllers);
91 mutex_unlock(&acpi_dma_lock);
92 kfree(adma);
93 return 0;
94 }
95
96 mutex_unlock(&acpi_dma_lock);
97 return -ENODEV;
98}
99EXPORT_SYMBOL_GPL(acpi_dma_controller_free);
100
101static void devm_acpi_dma_release(struct device *dev, void *res)
102{
103 acpi_dma_controller_free(dev);
104}
105
106/**
107 * devm_acpi_dma_controller_register - resource managed acpi_dma_controller_register()
108 * @dev: device that is registering this DMA controller
109 * @acpi_dma_xlate: translation function
110 * @data pointer to controller specific data
111 *
112 * Managed acpi_dma_controller_register(). DMA controller registered by this
113 * function are automatically freed on driver detach. See
114 * acpi_dma_controller_register() for more information.
115 */
116int devm_acpi_dma_controller_register(struct device *dev,
117 struct dma_chan *(*acpi_dma_xlate)
118 (struct acpi_dma_spec *, struct acpi_dma *),
119 void *data)
120{
121 void *res;
122 int ret;
123
124 res = devres_alloc(devm_acpi_dma_release, 0, GFP_KERNEL);
125 if (!res)
126 return -ENOMEM;
127
128 ret = acpi_dma_controller_register(dev, acpi_dma_xlate, data);
129 if (ret) {
130 devres_free(res);
131 return ret;
132 }
133 devres_add(dev, res);
134 return 0;
135}
136EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_register);
137
138/**
139 * devm_acpi_dma_controller_free - resource managed acpi_dma_controller_free()
140 *
141 * Unregister a DMA controller registered with
142 * devm_acpi_dma_controller_register(). Normally this function will not need to
143 * be called and the resource management code will ensure that the resource is
144 * freed.
145 */
146void devm_acpi_dma_controller_free(struct device *dev)
147{
148 WARN_ON(devres_destroy(dev, devm_acpi_dma_release, NULL, NULL));
149}
150EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_free);
151
152struct acpi_dma_parser_data {
153 struct acpi_dma_spec dma_spec;
154 size_t index;
155 size_t n;
156};
157
158/**
159 * acpi_dma_parse_fixed_dma - Parse FixedDMA ACPI resources to a DMA specifier
160 * @res: struct acpi_resource to get FixedDMA resources from
161 * @data: pointer to a helper struct acpi_dma_parser_data
162 */
163static int acpi_dma_parse_fixed_dma(struct acpi_resource *res, void *data)
164{
165 struct acpi_dma_parser_data *pdata = data;
166
167 if (res->type == ACPI_RESOURCE_TYPE_FIXED_DMA) {
168 struct acpi_resource_fixed_dma *dma = &res->data.fixed_dma;
169
170 if (pdata->n++ == pdata->index) {
171 pdata->dma_spec.chan_id = dma->channels;
172 pdata->dma_spec.slave_id = dma->request_lines;
173 }
174 }
175
176 /* Tell the ACPI core to skip this resource */
177 return 1;
178}
179
180/**
181 * acpi_dma_request_slave_chan_by_index - Get the DMA slave channel
182 * @dev: struct device to get DMA request from
183 * @index: index of FixedDMA descriptor for @dev
184 *
185 * Returns pointer to appropriate dma channel on success or NULL on error.
186 */
187struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
188 size_t index)
189{
190 struct acpi_dma_parser_data pdata;
191 struct acpi_dma_spec *dma_spec = &pdata.dma_spec;
192 struct list_head resource_list;
193 struct acpi_device *adev;
194 struct acpi_dma *adma;
195 struct dma_chan *chan = NULL;
196
197 /* Check if the device was enumerated by ACPI */
198 if (!dev || !ACPI_HANDLE(dev))
199 return NULL;
200
201 if (acpi_bus_get_device(ACPI_HANDLE(dev), &adev))
202 return NULL;
203
204 memset(&pdata, 0, sizeof(pdata));
205 pdata.index = index;
206
207 /* Initial values for the request line and channel */
208 dma_spec->chan_id = -1;
209 dma_spec->slave_id = -1;
210
211 INIT_LIST_HEAD(&resource_list);
212 acpi_dev_get_resources(adev, &resource_list,
213 acpi_dma_parse_fixed_dma, &pdata);
214 acpi_dev_free_resource_list(&resource_list);
215
216 if (dma_spec->slave_id < 0 || dma_spec->chan_id < 0)
217 return NULL;
218
219 mutex_lock(&acpi_dma_lock);
220
221 list_for_each_entry(adma, &acpi_dma_list, dma_controllers) {
222 dma_spec->dev = adma->dev;
223 chan = adma->acpi_dma_xlate(dma_spec, adma);
224 if (chan)
225 break;
226 }
227
228 mutex_unlock(&acpi_dma_lock);
229 return chan;
230}
231EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_index);
232
233/**
234 * acpi_dma_request_slave_chan_by_name - Get the DMA slave channel
235 * @dev: struct device to get DMA request from
236 * @name: represents corresponding FixedDMA descriptor for @dev
237 *
238 * In order to support both Device Tree and ACPI in a single driver we
239 * translate the names "tx" and "rx" here based on the most common case where
240 * the first FixedDMA descriptor is TX and second is RX.
241 *
242 * Returns pointer to appropriate dma channel on success or NULL on error.
243 */
244struct dma_chan *acpi_dma_request_slave_chan_by_name(struct device *dev,
245 const char *name)
246{
247 size_t index;
248
249 if (!strcmp(name, "tx"))
250 index = 0;
251 else if (!strcmp(name, "rx"))
252 index = 1;
253 else
254 return NULL;
255
256 return acpi_dma_request_slave_chan_by_index(dev, index);
257}
258EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_name);
259
260/**
261 * acpi_dma_simple_xlate - Simple ACPI DMA engine translation helper
262 * @dma_spec: pointer to ACPI DMA specifier
263 * @adma: pointer to ACPI DMA controller data
264 *
265 * A simple translation function for ACPI based devices. Passes &struct
266 * dma_spec to the DMA controller driver provided filter function. Returns
267 * pointer to the channel if found or %NULL otherwise.
268 */
269struct dma_chan *acpi_dma_simple_xlate(struct acpi_dma_spec *dma_spec,
270 struct acpi_dma *adma)
271{
272 struct acpi_dma_filter_info *info = adma->data;
273
274 if (!info || !info->filter_fn)
275 return NULL;
276
277 return dma_request_channel(info->dma_cap, info->filter_fn, dma_spec);
278}
279EXPORT_SYMBOL_GPL(acpi_dma_simple_xlate);
diff --git a/include/linux/acpi_dma.h b/include/linux/acpi_dma.h
new file mode 100644
index 000000000000..d09deabc7bf6
--- /dev/null
+++ b/include/linux/acpi_dma.h
@@ -0,0 +1,116 @@
1/*
2 * ACPI helpers for DMA request / controller
3 *
4 * Based on of_dma.h
5 *
6 * Copyright (C) 2013, Intel Corporation
7 * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#ifndef __LINUX_ACPI_DMA_H
15#define __LINUX_ACPI_DMA_H
16
17#include <linux/list.h>
18#include <linux/device.h>
19#include <linux/dmaengine.h>
20
21/**
22 * struct acpi_dma_spec - slave device DMA resources
23 * @chan_id: channel unique id
24 * @slave_id: request line unique id
25 * @dev: struct device of the DMA controller to be used in the filter
26 * function
27 */
28struct acpi_dma_spec {
29 int chan_id;
30 int slave_id;
31 struct device *dev;
32};
33
34/**
35 * struct acpi_dma - representation of the registered DMAC
36 * @dma_controllers: linked list node
37 * @dev: struct device of this controller
38 * @acpi_dma_xlate: callback function to find a suitable channel
39 * @data: private data used by a callback function
40 */
41struct acpi_dma {
42 struct list_head dma_controllers;
43 struct device *dev;
44 struct dma_chan *(*acpi_dma_xlate)
45 (struct acpi_dma_spec *, struct acpi_dma *);
46 void *data;
47};
48
49/* Used with acpi_dma_simple_xlate() */
50struct acpi_dma_filter_info {
51 dma_cap_mask_t dma_cap;
52 dma_filter_fn filter_fn;
53};
54
55#ifdef CONFIG_DMA_ACPI
56
57int acpi_dma_controller_register(struct device *dev,
58 struct dma_chan *(*acpi_dma_xlate)
59 (struct acpi_dma_spec *, struct acpi_dma *),
60 void *data);
61int acpi_dma_controller_free(struct device *dev);
62int devm_acpi_dma_controller_register(struct device *dev,
63 struct dma_chan *(*acpi_dma_xlate)
64 (struct acpi_dma_spec *, struct acpi_dma *),
65 void *data);
66void devm_acpi_dma_controller_free(struct device *dev);
67
68struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
69 size_t index);
70struct dma_chan *acpi_dma_request_slave_chan_by_name(struct device *dev,
71 const char *name);
72
73struct dma_chan *acpi_dma_simple_xlate(struct acpi_dma_spec *dma_spec,
74 struct acpi_dma *adma);
75#else
76
77static inline int acpi_dma_controller_register(struct device *dev,
78 struct dma_chan *(*acpi_dma_xlate)
79 (struct acpi_dma_spec *, struct acpi_dma *),
80 void *data)
81{
82 return -ENODEV;
83}
84static inline int acpi_dma_controller_free(struct device *dev)
85{
86 return -ENODEV;
87}
88static inline int devm_acpi_dma_controller_register(struct device *dev,
89 struct dma_chan *(*acpi_dma_xlate)
90 (struct acpi_dma_spec *, struct acpi_dma *),
91 void *data)
92{
93 return -ENODEV;
94}
95static inline void devm_acpi_dma_controller_free(struct device *dev)
96{
97}
98
99static inline struct dma_chan *acpi_dma_request_slave_chan_by_index(
100 struct device *dev, size_t index)
101{
102 return NULL;
103}
104static inline struct dma_chan *acpi_dma_request_slave_chan_by_name(
105 struct device *dev, const char *name)
106{
107 return NULL;
108}
109
110#define acpi_dma_simple_xlate NULL
111
112#endif
113
114#define acpi_dma_request_slave_channel acpi_dma_request_slave_chan_by_index
115
116#endif /* __LINUX_ACPI_DMA_H */