aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma
diff options
context:
space:
mode:
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>2013-05-08 04:55:48 -0400
committerVinod Koul <vinod.koul@intel.com>2013-05-14 00:53:57 -0400
commitee8209fd026b074bb8eb75bece516a338a281b1b (patch)
tree2ab58c3517488dd4faeafaafb598ec891cce81f8 /drivers/dma
parentf722406faae2d073cc1d01063d1123c35425939e (diff)
dma: acpi-dma: parse CSRT to extract additional resources
Since we have CSRT only to get additional DMA controller resources, let's get rid of drivers/acpi/csrt.c and move its logic inside ACPI DMA helpers code. Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-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>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/acpi-dma.c172
1 files changed, 169 insertions, 3 deletions
diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c
index ba6fc62e9651..5a18f82f732a 100644
--- a/drivers/dma/acpi-dma.c
+++ b/drivers/dma/acpi-dma.c
@@ -4,7 +4,8 @@
4 * Based on of-dma.c 4 * Based on of-dma.c
5 * 5 *
6 * Copyright (C) 2013, Intel Corporation 6 * Copyright (C) 2013, Intel Corporation
7 * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> 7 * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
8 * Mika Westerberg <mika.westerberg@linux.intel.com>
8 * 9 *
9 * This program is free software; you can redistribute it and/or modify 10 * 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 * it under the terms of the GNU General Public License version 2 as
@@ -16,6 +17,7 @@
16#include <linux/list.h> 17#include <linux/list.h>
17#include <linux/mutex.h> 18#include <linux/mutex.h>
18#include <linux/slab.h> 19#include <linux/slab.h>
20#include <linux/ioport.h>
19#include <linux/acpi.h> 21#include <linux/acpi.h>
20#include <linux/acpi_dma.h> 22#include <linux/acpi_dma.h>
21 23
@@ -23,6 +25,117 @@ static LIST_HEAD(acpi_dma_list);
23static DEFINE_MUTEX(acpi_dma_lock); 25static DEFINE_MUTEX(acpi_dma_lock);
24 26
25/** 27/**
28 * acpi_dma_parse_resource_group - match device and parse resource group
29 * @grp: CSRT resource group
30 * @adev: ACPI device to match with
31 * @adma: struct acpi_dma of the given DMA controller
32 *
33 * Returns 1 on success, 0 when no information is available, or appropriate
34 * errno value on error.
35 *
36 * In order to match a device from DSDT table to the corresponding CSRT device
37 * we use MMIO address and IRQ.
38 */
39static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp,
40 struct acpi_device *adev, struct acpi_dma *adma)
41{
42 const struct acpi_csrt_shared_info *si;
43 struct list_head resource_list;
44 struct resource_list_entry *rentry;
45 resource_size_t mem = 0, irq = 0;
46 u32 vendor_id;
47 int ret;
48
49 if (grp->shared_info_length != sizeof(struct acpi_csrt_shared_info))
50 return -ENODEV;
51
52 INIT_LIST_HEAD(&resource_list);
53 ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
54 if (ret <= 0)
55 return 0;
56
57 list_for_each_entry(rentry, &resource_list, node) {
58 if (resource_type(&rentry->res) == IORESOURCE_MEM)
59 mem = rentry->res.start;
60 else if (resource_type(&rentry->res) == IORESOURCE_IRQ)
61 irq = rentry->res.start;
62 }
63
64 acpi_dev_free_resource_list(&resource_list);
65
66 /* Consider initial zero values as resource not found */
67 if (mem == 0 && irq == 0)
68 return 0;
69
70 si = (const struct acpi_csrt_shared_info *)&grp[1];
71
72 /* Match device by MMIO and IRQ */
73 if (si->mmio_base_low != mem || si->gsi_interrupt != irq)
74 return 0;
75
76 vendor_id = le32_to_cpu(grp->vendor_id);
77 dev_dbg(&adev->dev, "matches with %.4s%04X (rev %u)\n",
78 (char *)&vendor_id, grp->device_id, grp->revision);
79
80 /* Check if the request line range is available */
81 if (si->base_request_line == 0 && si->num_handshake_signals == 0)
82 return 0;
83
84 adma->base_request_line = si->base_request_line;
85 adma->end_request_line = si->base_request_line +
86 si->num_handshake_signals - 1;
87
88 dev_dbg(&adev->dev, "request line base: 0x%04x end: 0x%04x\n",
89 adma->base_request_line, adma->end_request_line);
90
91 return 1;
92}
93
94/**
95 * acpi_dma_parse_csrt - parse CSRT to exctract additional DMA resources
96 * @adev: ACPI device to match with
97 * @adma: struct acpi_dma of the given DMA controller
98 *
99 * CSRT or Core System Resources Table is a proprietary ACPI table
100 * introduced by Microsoft. This table can contain devices that are not in
101 * the system DSDT table. In particular DMA controllers might be described
102 * here.
103 *
104 * We are using this table to get the request line range of the specific DMA
105 * controller to be used later.
106 *
107 */
108static void acpi_dma_parse_csrt(struct acpi_device *adev, struct acpi_dma *adma)
109{
110 struct acpi_csrt_group *grp, *end;
111 struct acpi_table_csrt *csrt;
112 acpi_status status;
113 int ret;
114
115 status = acpi_get_table(ACPI_SIG_CSRT, 0,
116 (struct acpi_table_header **)&csrt);
117 if (ACPI_FAILURE(status)) {
118 if (status != AE_NOT_FOUND)
119 dev_warn(&adev->dev, "failed to get the CSRT table\n");
120 return;
121 }
122
123 grp = (struct acpi_csrt_group *)(csrt + 1);
124 end = (struct acpi_csrt_group *)((void *)csrt + csrt->header.length);
125
126 while (grp < end) {
127 ret = acpi_dma_parse_resource_group(grp, adev, adma);
128 if (ret < 0) {
129 dev_warn(&adev->dev,
130 "error in parsing resource group\n");
131 return;
132 }
133
134 grp = (struct acpi_csrt_group *)((void *)grp + grp->length);
135 }
136}
137
138/**
26 * acpi_dma_controller_register - Register a DMA controller to ACPI DMA helpers 139 * acpi_dma_controller_register - Register a DMA controller to ACPI DMA helpers
27 * @dev: struct device of DMA controller 140 * @dev: struct device of DMA controller
28 * @acpi_dma_xlate: translation function which converts a dma specifier 141 * @acpi_dma_xlate: translation function which converts a dma specifier
@@ -61,6 +174,8 @@ int acpi_dma_controller_register(struct device *dev,
61 adma->acpi_dma_xlate = acpi_dma_xlate; 174 adma->acpi_dma_xlate = acpi_dma_xlate;
62 adma->data = data; 175 adma->data = data;
63 176
177 acpi_dma_parse_csrt(adev, adma);
178
64 /* Now queue acpi_dma controller structure in list */ 179 /* Now queue acpi_dma controller structure in list */
65 mutex_lock(&acpi_dma_lock); 180 mutex_lock(&acpi_dma_lock);
66 list_add_tail(&adma->dma_controllers, &acpi_dma_list); 181 list_add_tail(&adma->dma_controllers, &acpi_dma_list);
@@ -149,6 +264,45 @@ void devm_acpi_dma_controller_free(struct device *dev)
149} 264}
150EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_free); 265EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_free);
151 266
267/**
268 * acpi_dma_update_dma_spec - prepare dma specifier to pass to translation function
269 * @adma: struct acpi_dma of DMA controller
270 * @dma_spec: dma specifier to update
271 *
272 * Returns 0, if no information is avaiable, -1 on mismatch, and 1 otherwise.
273 *
274 * Accordingly to ACPI 5.0 Specification Table 6-170 "Fixed DMA Resource
275 * Descriptor":
276 * DMA Request Line bits is a platform-relative number uniquely
277 * identifying the request line assigned. Request line-to-Controller
278 * mapping is done in a controller-specific OS driver.
279 * That's why we can safely adjust slave_id when the appropriate controller is
280 * found.
281 */
282static int acpi_dma_update_dma_spec(struct acpi_dma *adma,
283 struct acpi_dma_spec *dma_spec)
284{
285 /* Set link to the DMA controller device */
286 dma_spec->dev = adma->dev;
287
288 /* Check if the request line range is available */
289 if (adma->base_request_line == 0 && adma->end_request_line == 0)
290 return 0;
291
292 /* Check if slave_id falls to the range */
293 if (dma_spec->slave_id < adma->base_request_line ||
294 dma_spec->slave_id > adma->end_request_line)
295 return -1;
296
297 /*
298 * Here we adjust slave_id. It should be a relative number to the base
299 * request line.
300 */
301 dma_spec->slave_id -= adma->base_request_line;
302
303 return 1;
304}
305
152struct acpi_dma_parser_data { 306struct acpi_dma_parser_data {
153 struct acpi_dma_spec dma_spec; 307 struct acpi_dma_spec dma_spec;
154 size_t index; 308 size_t index;
@@ -193,6 +347,7 @@ struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
193 struct acpi_device *adev; 347 struct acpi_device *adev;
194 struct acpi_dma *adma; 348 struct acpi_dma *adma;
195 struct dma_chan *chan = NULL; 349 struct dma_chan *chan = NULL;
350 int found;
196 351
197 /* Check if the device was enumerated by ACPI */ 352 /* Check if the device was enumerated by ACPI */
198 if (!dev || !ACPI_HANDLE(dev)) 353 if (!dev || !ACPI_HANDLE(dev))
@@ -219,9 +374,20 @@ struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
219 mutex_lock(&acpi_dma_lock); 374 mutex_lock(&acpi_dma_lock);
220 375
221 list_for_each_entry(adma, &acpi_dma_list, dma_controllers) { 376 list_for_each_entry(adma, &acpi_dma_list, dma_controllers) {
222 dma_spec->dev = adma->dev; 377 /*
378 * We are not going to call translation function if slave_id
379 * doesn't fall to the request range.
380 */
381 found = acpi_dma_update_dma_spec(adma, dma_spec);
382 if (found < 0)
383 continue;
223 chan = adma->acpi_dma_xlate(dma_spec, adma); 384 chan = adma->acpi_dma_xlate(dma_spec, adma);
224 if (chan) 385 /*
386 * Try to get a channel only from the DMA controller that
387 * matches the slave_id. See acpi_dma_update_dma_spec()
388 * description for the details.
389 */
390 if (found > 0 || chan)
225 break; 391 break;
226 } 392 }
227 393