Blame view

drivers/dma/acpi-dma.c 13 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
2
3
4
5
6
7
  /*
   * ACPI helpers for DMA request / controller
   *
   * Based on of-dma.c
   *
   * Copyright (C) 2013, Intel Corporation
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
8
9
   * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
   *	    Mika Westerberg <mika.westerberg@linux.intel.com>
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
10
11
12
   */
  
  #include <linux/device.h>
a6bc33237   Andy Shevchenko   dmaengine: acpi: ...
13
  #include <linux/dma-mapping.h>
0f6a928d0   Andy Shevchenko   acpi-dma: convert...
14
  #include <linux/err.h>
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
15
  #include <linux/module.h>
f94cf9f4c   Andy Shevchenko   dmaengine: acpi-d...
16
  #include <linux/kernel.h>
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
17
18
19
  #include <linux/list.h>
  #include <linux/mutex.h>
  #include <linux/slab.h>
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
20
  #include <linux/ioport.h>
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
21
22
  #include <linux/acpi.h>
  #include <linux/acpi_dma.h>
3f4232ee8   Mika Westerberg   acpi-dma: Add sup...
23
  #include <linux/property.h>
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
24
25
26
27
28
  
  static LIST_HEAD(acpi_dma_list);
  static DEFINE_MUTEX(acpi_dma_lock);
  
  /**
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
29
30
31
32
33
   * acpi_dma_parse_resource_group - match device and parse resource group
   * @grp:	CSRT resource group
   * @adev:	ACPI device to match with
   * @adma:	struct acpi_dma of the given DMA controller
   *
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
34
35
   * In order to match a device from DSDT table to the corresponding CSRT device
   * we use MMIO address and IRQ.
39d144781   Andy Shevchenko   acpi-dma: align d...
36
37
38
39
   *
   * Return:
   * 1 on success, 0 when no information is available, or appropriate errno value
   * on error.
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
40
41
42
43
44
45
   */
  static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp,
  		struct acpi_device *adev, struct acpi_dma *adma)
  {
  	const struct acpi_csrt_shared_info *si;
  	struct list_head resource_list;
90e978206   Jiang Liu   resources: Move s...
46
  	struct resource_entry *rentry;
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
47
  	resource_size_t mem = 0, irq = 0;
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
48
49
50
51
52
53
54
55
56
57
58
  	int ret;
  
  	if (grp->shared_info_length != sizeof(struct acpi_csrt_shared_info))
  		return -ENODEV;
  
  	INIT_LIST_HEAD(&resource_list);
  	ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
  	if (ret <= 0)
  		return 0;
  
  	list_for_each_entry(rentry, &resource_list, node) {
90e978206   Jiang Liu   resources: Move s...
59
60
61
62
  		if (resource_type(rentry->res) == IORESOURCE_MEM)
  			mem = rentry->res->start;
  		else if (resource_type(rentry->res) == IORESOURCE_IRQ)
  			irq = rentry->res->start;
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
63
64
65
66
67
68
69
70
71
72
73
  	}
  
  	acpi_dev_free_resource_list(&resource_list);
  
  	/* Consider initial zero values as resource not found */
  	if (mem == 0 && irq == 0)
  		return 0;
  
  	si = (const struct acpi_csrt_shared_info *)&grp[1];
  
  	/* Match device by MMIO and IRQ */
f94cf9f4c   Andy Shevchenko   dmaengine: acpi-d...
74
75
76
  	if (si->mmio_base_low != lower_32_bits(mem) ||
  	    si->mmio_base_high != upper_32_bits(mem) ||
  	    si->gsi_interrupt != irq)
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
77
  		return 0;
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
78
79
  	dev_dbg(&adev->dev, "matches with %.4s%04X (rev %u)
  ",
b4d6d3367   Andy Shevchenko   acpi-dma: remove ...
80
  		(char *)&grp->vendor_id, grp->device_id, grp->revision);
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
81
82
83
84
  
  	/* Check if the request line range is available */
  	if (si->base_request_line == 0 && si->num_handshake_signals == 0)
  		return 0;
a6bc33237   Andy Shevchenko   dmaengine: acpi: ...
85
86
87
88
89
  	/* Set up DMA mask based on value from CSRT */
  	ret = dma_coerce_mask_and_coherent(&adev->dev,
  					   DMA_BIT_MASK(si->dma_address_width));
  	if (ret)
  		return 0;
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
  	adma->base_request_line = si->base_request_line;
  	adma->end_request_line = si->base_request_line +
  				 si->num_handshake_signals - 1;
  
  	dev_dbg(&adev->dev, "request line base: 0x%04x end: 0x%04x
  ",
  		adma->base_request_line, adma->end_request_line);
  
  	return 1;
  }
  
  /**
   * acpi_dma_parse_csrt - parse CSRT to exctract additional DMA resources
   * @adev:	ACPI device to match with
   * @adma:	struct acpi_dma of the given DMA controller
   *
   * CSRT or Core System Resources Table is a proprietary ACPI table
   * introduced by Microsoft. This table can contain devices that are not in
   * the system DSDT table. In particular DMA controllers might be described
   * here.
   *
   * We are using this table to get the request line range of the specific DMA
   * controller to be used later.
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
   */
  static void acpi_dma_parse_csrt(struct acpi_device *adev, struct acpi_dma *adma)
  {
  	struct acpi_csrt_group *grp, *end;
  	struct acpi_table_csrt *csrt;
  	acpi_status status;
  	int ret;
  
  	status = acpi_get_table(ACPI_SIG_CSRT, 0,
  				(struct acpi_table_header **)&csrt);
  	if (ACPI_FAILURE(status)) {
  		if (status != AE_NOT_FOUND)
  			dev_warn(&adev->dev, "failed to get the CSRT table
  ");
  		return;
  	}
  
  	grp = (struct acpi_csrt_group *)(csrt + 1);
  	end = (struct acpi_csrt_group *)((void *)csrt + csrt->header.length);
  
  	while (grp < end) {
  		ret = acpi_dma_parse_resource_group(grp, adev, adma);
  		if (ret < 0) {
  			dev_warn(&adev->dev,
  				 "error in parsing resource group
  ");
7eb48dd09   Hanjun Guo   dmaengine: acpi: ...
139
  			break;
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
140
141
142
143
  		}
  
  		grp = (struct acpi_csrt_group *)((void *)grp + grp->length);
  	}
7eb48dd09   Hanjun Guo   dmaengine: acpi: ...
144
145
  
  	acpi_put_table((struct acpi_table_header *)csrt);
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
146
147
148
  }
  
  /**
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
149
150
151
152
   * acpi_dma_controller_register - Register a DMA controller to ACPI DMA helpers
   * @dev:		struct device of DMA controller
   * @acpi_dma_xlate:	translation function which converts a dma specifier
   *			into a dma_chan structure
4b8584bac   Andy Shevchenko   dmaengine: acpi: ...
153
   * @data:		pointer to controller specific data to be used by
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
154
155
   *			translation function
   *
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
156
157
   * Allocated memory should be freed with appropriate acpi_dma_controller_free()
   * call.
39d144781   Andy Shevchenko   acpi-dma: align d...
158
159
160
   *
   * Return:
   * 0 on success or appropriate errno value on error.
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
161
162
163
164
165
166
167
168
169
170
171
172
173
   */
  int acpi_dma_controller_register(struct device *dev,
  		struct dma_chan *(*acpi_dma_xlate)
  		(struct acpi_dma_spec *, struct acpi_dma *),
  		void *data)
  {
  	struct acpi_device *adev;
  	struct acpi_dma	*adma;
  
  	if (!dev || !acpi_dma_xlate)
  		return -EINVAL;
  
  	/* Check if the device was enumerated by ACPI */
aff1e0cee   Jarkko Nikula   dmaengine: acpi: ...
174
175
  	adev = ACPI_COMPANION(dev);
  	if (!adev)
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
176
177
178
179
180
181
182
183
184
  		return -EINVAL;
  
  	adma = kzalloc(sizeof(*adma), GFP_KERNEL);
  	if (!adma)
  		return -ENOMEM;
  
  	adma->dev = dev;
  	adma->acpi_dma_xlate = acpi_dma_xlate;
  	adma->data = data;
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
185
  	acpi_dma_parse_csrt(adev, adma);
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
  	/* Now queue acpi_dma controller structure in list */
  	mutex_lock(&acpi_dma_lock);
  	list_add_tail(&adma->dma_controllers, &acpi_dma_list);
  	mutex_unlock(&acpi_dma_lock);
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(acpi_dma_controller_register);
  
  /**
   * acpi_dma_controller_free - Remove a DMA controller from ACPI DMA helpers list
   * @dev:	struct device of DMA controller
   *
   * Memory allocated by acpi_dma_controller_register() is freed here.
39d144781   Andy Shevchenko   acpi-dma: align d...
200
201
202
   *
   * Return:
   * 0 on success or appropriate errno value on error.
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
   */
  int acpi_dma_controller_free(struct device *dev)
  {
  	struct acpi_dma *adma;
  
  	if (!dev)
  		return -EINVAL;
  
  	mutex_lock(&acpi_dma_lock);
  
  	list_for_each_entry(adma, &acpi_dma_list, dma_controllers)
  		if (adma->dev == dev) {
  			list_del(&adma->dma_controllers);
  			mutex_unlock(&acpi_dma_lock);
  			kfree(adma);
  			return 0;
  		}
  
  	mutex_unlock(&acpi_dma_lock);
  	return -ENODEV;
  }
  EXPORT_SYMBOL_GPL(acpi_dma_controller_free);
  
  static void devm_acpi_dma_release(struct device *dev, void *res)
  {
  	acpi_dma_controller_free(dev);
  }
  
  /**
   * devm_acpi_dma_controller_register - resource managed acpi_dma_controller_register()
   * @dev:		device that is registering this DMA controller
   * @acpi_dma_xlate:	translation function
4b8584bac   Andy Shevchenko   dmaengine: acpi: ...
235
   * @data:		pointer to controller specific data
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
236
237
238
239
   *
   * Managed acpi_dma_controller_register(). DMA controller registered by this
   * function are automatically freed on driver detach. See
   * acpi_dma_controller_register() for more information.
39d144781   Andy Shevchenko   acpi-dma: align d...
240
241
242
   *
   * Return:
   * 0 on success or appropriate errno value on error.
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
   */
  int devm_acpi_dma_controller_register(struct device *dev,
  		struct dma_chan *(*acpi_dma_xlate)
  		(struct acpi_dma_spec *, struct acpi_dma *),
  		void *data)
  {
  	void *res;
  	int ret;
  
  	res = devres_alloc(devm_acpi_dma_release, 0, GFP_KERNEL);
  	if (!res)
  		return -ENOMEM;
  
  	ret = acpi_dma_controller_register(dev, acpi_dma_xlate, data);
  	if (ret) {
  		devres_free(res);
  		return ret;
  	}
  	devres_add(dev, res);
  	return 0;
  }
  EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_register);
  
  /**
   * devm_acpi_dma_controller_free - resource managed acpi_dma_controller_free()
4b8584bac   Andy Shevchenko   dmaengine: acpi: ...
268
   * @dev:	device that is unregistering as DMA controller
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
269
270
271
272
273
274
275
276
   *
   * Unregister a DMA controller registered with
   * devm_acpi_dma_controller_register(). Normally this function will not need to
   * be called and the resource management code will ensure that the resource is
   * freed.
   */
  void devm_acpi_dma_controller_free(struct device *dev)
  {
8f0125838   Andy Shevchenko   acpi-dma: use dev...
277
  	WARN_ON(devres_release(dev, devm_acpi_dma_release, NULL, NULL));
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
278
279
  }
  EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_free);
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
280
281
282
283
284
  /**
   * acpi_dma_update_dma_spec - prepare dma specifier to pass to translation function
   * @adma:	struct acpi_dma of DMA controller
   * @dma_spec:	dma specifier to update
   *
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
285
286
287
288
289
290
291
   * Accordingly to ACPI 5.0 Specification Table 6-170 "Fixed DMA Resource
   * Descriptor":
   *	DMA Request Line bits is a platform-relative number uniquely
   *	identifying the request line assigned. Request line-to-Controller
   *	mapping is done in a controller-specific OS driver.
   * That's why we can safely adjust slave_id when the appropriate controller is
   * found.
39d144781   Andy Shevchenko   acpi-dma: align d...
292
293
294
   *
   * Return:
   * 0, if no information is avaiable, -1 on mismatch, and 1 otherwise.
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
   */
  static int acpi_dma_update_dma_spec(struct acpi_dma *adma,
  		struct acpi_dma_spec *dma_spec)
  {
  	/* Set link to the DMA controller device */
  	dma_spec->dev = adma->dev;
  
  	/* Check if the request line range is available */
  	if (adma->base_request_line == 0 && adma->end_request_line == 0)
  		return 0;
  
  	/* Check if slave_id falls to the range */
  	if (dma_spec->slave_id < adma->base_request_line ||
  	    dma_spec->slave_id > adma->end_request_line)
  		return -1;
  
  	/*
  	 * Here we adjust slave_id. It should be a relative number to the base
  	 * request line.
  	 */
  	dma_spec->slave_id -= adma->base_request_line;
  
  	return 1;
  }
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
  struct acpi_dma_parser_data {
  	struct acpi_dma_spec dma_spec;
  	size_t index;
  	size_t n;
  };
  
  /**
   * acpi_dma_parse_fixed_dma - Parse FixedDMA ACPI resources to a DMA specifier
   * @res:	struct acpi_resource to get FixedDMA resources from
   * @data:	pointer to a helper struct acpi_dma_parser_data
   */
  static int acpi_dma_parse_fixed_dma(struct acpi_resource *res, void *data)
  {
  	struct acpi_dma_parser_data *pdata = data;
  
  	if (res->type == ACPI_RESOURCE_TYPE_FIXED_DMA) {
  		struct acpi_resource_fixed_dma *dma = &res->data.fixed_dma;
  
  		if (pdata->n++ == pdata->index) {
  			pdata->dma_spec.chan_id = dma->channels;
  			pdata->dma_spec.slave_id = dma->request_lines;
  		}
  	}
  
  	/* Tell the ACPI core to skip this resource */
  	return 1;
  }
  
  /**
   * acpi_dma_request_slave_chan_by_index - Get the DMA slave channel
   * @dev:	struct device to get DMA request from
   * @index:	index of FixedDMA descriptor for @dev
   *
39d144781   Andy Shevchenko   acpi-dma: align d...
352
   * Return:
0f6a928d0   Andy Shevchenko   acpi-dma: convert...
353
   * Pointer to appropriate dma channel on success or an error pointer.
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
354
355
356
357
358
359
   */
  struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
  		size_t index)
  {
  	struct acpi_dma_parser_data pdata;
  	struct acpi_dma_spec *dma_spec = &pdata.dma_spec;
6915ef1cb   Andy Shevchenko   dmaengine: acpi: ...
360
  	struct acpi_device *adev = ACPI_COMPANION(dev);
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
361
  	struct list_head resource_list;
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
362
363
  	struct acpi_dma *adma;
  	struct dma_chan *chan = NULL;
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
364
  	int found;
6915ef1cb   Andy Shevchenko   dmaengine: acpi: ...
365
  	int ret;
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
366
367
368
369
370
371
372
373
374
  
  	memset(&pdata, 0, sizeof(pdata));
  	pdata.index = index;
  
  	/* Initial values for the request line and channel */
  	dma_spec->chan_id = -1;
  	dma_spec->slave_id = -1;
  
  	INIT_LIST_HEAD(&resource_list);
6915ef1cb   Andy Shevchenko   dmaengine: acpi: ...
375
376
  	ret = acpi_dev_get_resources(adev, &resource_list,
  				     acpi_dma_parse_fixed_dma, &pdata);
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
377
  	acpi_dev_free_resource_list(&resource_list);
6915ef1cb   Andy Shevchenko   dmaengine: acpi: ...
378
379
  	if (ret < 0)
  		return ERR_PTR(ret);
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
380
381
  
  	if (dma_spec->slave_id < 0 || dma_spec->chan_id < 0)
0f6a928d0   Andy Shevchenko   acpi-dma: convert...
382
  		return ERR_PTR(-ENODEV);
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
383
384
385
386
  
  	mutex_lock(&acpi_dma_lock);
  
  	list_for_each_entry(adma, &acpi_dma_list, dma_controllers) {
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
387
388
389
390
391
392
393
  		/*
  		 * We are not going to call translation function if slave_id
  		 * doesn't fall to the request range.
  		 */
  		found = acpi_dma_update_dma_spec(adma, dma_spec);
  		if (found < 0)
  			continue;
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
394
  		chan = adma->acpi_dma_xlate(dma_spec, adma);
ee8209fd0   Andy Shevchenko   dma: acpi-dma: pa...
395
396
397
398
399
400
  		/*
  		 * Try to get a channel only from the DMA controller that
  		 * matches the slave_id. See acpi_dma_update_dma_spec()
  		 * description for the details.
  		 */
  		if (found > 0 || chan)
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
401
402
403
404
  			break;
  	}
  
  	mutex_unlock(&acpi_dma_lock);
0f6a928d0   Andy Shevchenko   acpi-dma: convert...
405
  	return chan ? chan : ERR_PTR(-EPROBE_DEFER);
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
406
407
408
409
410
411
412
413
414
415
416
417
  }
  EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_index);
  
  /**
   * acpi_dma_request_slave_chan_by_name - Get the DMA slave channel
   * @dev:	struct device to get DMA request from
   * @name:	represents corresponding FixedDMA descriptor for @dev
   *
   * In order to support both Device Tree and ACPI in a single driver we
   * translate the names "tx" and "rx" here based on the most common case where
   * the first FixedDMA descriptor is TX and second is RX.
   *
3f4232ee8   Mika Westerberg   acpi-dma: Add sup...
418
419
420
421
   * If the device has "dma-names" property the FixedDMA descriptor indices
   * are retrieved based on those. Otherwise the function falls back using
   * hardcoded indices.
   *
39d144781   Andy Shevchenko   acpi-dma: align d...
422
   * Return:
0f6a928d0   Andy Shevchenko   acpi-dma: convert...
423
   * Pointer to appropriate dma channel on success or an error pointer.
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
424
425
426
427
   */
  struct dma_chan *acpi_dma_request_slave_chan_by_name(struct device *dev,
  		const char *name)
  {
3f4232ee8   Mika Westerberg   acpi-dma: Add sup...
428
429
430
431
432
433
434
435
436
437
438
  	int index;
  
  	index = device_property_match_string(dev, "dma-names", name);
  	if (index < 0) {
  		if (!strcmp(name, "tx"))
  			index = 0;
  		else if (!strcmp(name, "rx"))
  			index = 1;
  		else
  			return ERR_PTR(-ENODEV);
  	}
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
439

36bf8fc42   Andy Shevchenko   dmaengine: acpi-d...
440
441
  	dev_dbg(dev, "Looking for DMA channel \"%s\" at index %d...
  ", name, index);
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
442
443
444
445
446
447
448
449
450
451
  	return acpi_dma_request_slave_chan_by_index(dev, index);
  }
  EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_name);
  
  /**
   * acpi_dma_simple_xlate - Simple ACPI DMA engine translation helper
   * @dma_spec: pointer to ACPI DMA specifier
   * @adma: pointer to ACPI DMA controller data
   *
   * A simple translation function for ACPI based devices. Passes &struct
39d144781   Andy Shevchenko   acpi-dma: align d...
452
453
454
455
   * dma_spec to the DMA controller driver provided filter function.
   *
   * Return:
   * Pointer to the channel if found or %NULL otherwise.
1b2e98bc1   Andy Shevchenko   dma: acpi-dma: in...
456
457
458
459
460
461
462
463
464
465
466
467
   */
  struct dma_chan *acpi_dma_simple_xlate(struct acpi_dma_spec *dma_spec,
  		struct acpi_dma *adma)
  {
  	struct acpi_dma_filter_info *info = adma->data;
  
  	if (!info || !info->filter_fn)
  		return NULL;
  
  	return dma_request_channel(info->dma_cap, info->filter_fn, dma_spec);
  }
  EXPORT_SYMBOL_GPL(acpi_dma_simple_xlate);