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