summaryrefslogtreecommitdiff
path: root/drivers/dma/acpi-dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma/acpi-dma.c')
-rw-r--r--drivers/dma/acpi-dma.c101
1 files changed, 48 insertions, 53 deletions
diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c
index 4a748c3435d7..2abbe11e797e 100644
--- a/drivers/dma/acpi-dma.c
+++ b/drivers/dma/acpi-dma.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ACPI helpers for DMA request / controller
*
@@ -6,23 +7,23 @@
* Copyright (C) 2013, Intel Corporation
* Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
* Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
+#include <linux/acpi.h>
+#include <linux/acpi_dma.h>
#include <linux/device.h>
+#include <linux/dma-mapping.h>
#include <linux/err.h>
-#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/acpi.h>
-#include <linux/acpi_dma.h>
#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
static LIST_HEAD(acpi_dma_list);
static DEFINE_MUTEX(acpi_dma_lock);
@@ -72,10 +73,22 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp,
si = (const struct acpi_csrt_shared_info *)&grp[1];
- /* Match device by MMIO and IRQ */
+ /* Match device by MMIO */
if (si->mmio_base_low != lower_32_bits(mem) ||
- si->mmio_base_high != upper_32_bits(mem) ||
- si->gsi_interrupt != irq)
+ si->mmio_base_high != upper_32_bits(mem))
+ return 0;
+
+ /*
+ * acpi_gsi_to_irq() can't be used because some platforms do not save
+ * registered IRQs in the MP table. Instead we just try to register
+ * the GSI, which is the core part of the above mentioned function.
+ */
+ ret = acpi_register_gsi(NULL, si->gsi_interrupt, si->interrupt_mode, si->interrupt_polarity);
+ if (ret < 0)
+ return 0;
+
+ /* Match device by Linux vIRQ */
+ if (ret != irq)
return 0;
dev_dbg(&adev->dev, "matches with %.4s%04X (rev %u)\n",
@@ -85,6 +98,12 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp,
if (si->base_request_line == 0 && si->num_handshake_signals == 0)
return 0;
+ /* 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;
+
adma->base_request_line = si->base_request_line;
adma->end_request_line = si->base_request_line +
si->num_handshake_signals - 1;
@@ -96,7 +115,7 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp,
}
/**
- * acpi_dma_parse_csrt - parse CSRT to exctract additional DMA resources
+ * acpi_dma_parse_csrt - parse CSRT to extract additional DMA resources
* @adev: ACPI device to match with
* @adma: struct acpi_dma of the given DMA controller
*
@@ -131,11 +150,13 @@ static void acpi_dma_parse_csrt(struct acpi_device *adev, struct acpi_dma *adma)
if (ret < 0) {
dev_warn(&adev->dev,
"error in parsing resource group\n");
- return;
+ break;
}
grp = (struct acpi_csrt_group *)((void *)grp + grp->length);
}
+
+ acpi_put_table((struct acpi_table_header *)csrt);
}
/**
@@ -143,7 +164,7 @@ static void acpi_dma_parse_csrt(struct acpi_device *adev, struct acpi_dma *adma)
* @dev: struct device of DMA controller
* @acpi_dma_xlate: translation function which converts a dma specifier
* into a dma_chan structure
- * @data pointer to controller specific data to be used by
+ * @data: pointer to controller specific data to be used by
* translation function
*
* Allocated memory should be freed with appropriate acpi_dma_controller_free()
@@ -218,7 +239,7 @@ int acpi_dma_controller_free(struct device *dev)
}
EXPORT_SYMBOL_GPL(acpi_dma_controller_free);
-static void devm_acpi_dma_release(struct device *dev, void *res)
+static void devm_acpi_dma_free(void *dev)
{
acpi_dma_controller_free(dev);
}
@@ -227,7 +248,7 @@ static void devm_acpi_dma_release(struct device *dev, void *res)
* devm_acpi_dma_controller_register - resource managed acpi_dma_controller_register()
* @dev: device that is registering this DMA controller
* @acpi_dma_xlate: translation function
- * @data pointer to controller specific data
+ * @data: pointer to controller specific data
*
* Managed acpi_dma_controller_register(). DMA controller registered by this
* function are automatically freed on driver detach. See
@@ -241,36 +262,15 @@ int devm_acpi_dma_controller_register(struct device *dev,
(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);
+ if (ret)
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()
- *
- * 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)
-{
- WARN_ON(devres_release(dev, devm_acpi_dma_release, NULL, NULL));
+ return devm_add_action_or_reset(dev, devm_acpi_dma_free, dev);
}
-EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_free);
+EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_register);
/**
* acpi_dma_update_dma_spec - prepare dma specifier to pass to translation function
@@ -286,7 +286,7 @@ EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_free);
* found.
*
* Return:
- * 0, if no information is avaiable, -1 on mismatch, and 1 otherwise.
+ * 0, if no information is available, -1 on mismatch, and 1 otherwise.
*/
static int acpi_dma_update_dma_spec(struct acpi_dma *adma,
struct acpi_dma_spec *dma_spec)
@@ -353,19 +353,12 @@ struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
{
struct acpi_dma_parser_data pdata;
struct acpi_dma_spec *dma_spec = &pdata.dma_spec;
+ struct acpi_device *adev = ACPI_COMPANION(dev);
struct list_head resource_list;
- struct acpi_device *adev;
struct acpi_dma *adma;
struct dma_chan *chan = NULL;
int found;
-
- /* Check if the device was enumerated by ACPI */
- if (!dev)
- return ERR_PTR(-ENODEV);
-
- adev = ACPI_COMPANION(dev);
- if (!adev)
- return ERR_PTR(-ENODEV);
+ int ret;
memset(&pdata, 0, sizeof(pdata));
pdata.index = index;
@@ -375,9 +368,11 @@ struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
dma_spec->slave_id = -1;
INIT_LIST_HEAD(&resource_list);
- acpi_dev_get_resources(adev, &resource_list,
- acpi_dma_parse_fixed_dma, &pdata);
+ ret = acpi_dev_get_resources(adev, &resource_list,
+ acpi_dma_parse_fixed_dma, &pdata);
acpi_dev_free_resource_list(&resource_list);
+ if (ret < 0)
+ return ERR_PTR(ret);
if (dma_spec->slave_id < 0 || dma_spec->chan_id < 0)
return ERR_PTR(-ENODEV);