linux/drivers/acpi/resource.c
<<
>>
Prefs
   1/*
   2 * drivers/acpi/resource.c - ACPI device resources interpretation.
   3 *
   4 * Copyright (C) 2012, Intel Corp.
   5 * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
   6 *
   7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   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 published
  11 *  by the Free Software Foundation.
  12 *
  13 *  This program is distributed in the hope that it will be useful, but
  14 *  WITHOUT ANY WARRANTY; without even the implied warranty of
  15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16 *  General Public License for more details.
  17 *
  18 *  You should have received a copy of the GNU General Public License along
  19 *  with this program; if not, write to the Free Software Foundation, Inc.,
  20 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  21 *
  22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  23 */
  24
  25#include <linux/acpi.h>
  26#include <linux/device.h>
  27#include <linux/export.h>
  28#include <linux/ioport.h>
  29#include <linux/slab.h>
  30
  31#ifdef CONFIG_X86
  32#define valid_IRQ(i) (((i) != 0) && ((i) != 2))
  33#else
  34#define valid_IRQ(i) (true)
  35#endif
  36
  37static unsigned long acpi_dev_memresource_flags(u64 len, u8 write_protect,
  38                                                bool window)
  39{
  40        unsigned long flags = IORESOURCE_MEM;
  41
  42        if (len == 0)
  43                flags |= IORESOURCE_DISABLED;
  44
  45        if (write_protect == ACPI_READ_WRITE_MEMORY)
  46                flags |= IORESOURCE_MEM_WRITEABLE;
  47
  48        if (window)
  49                flags |= IORESOURCE_WINDOW;
  50
  51        return flags;
  52}
  53
  54static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len,
  55                                     u8 write_protect)
  56{
  57        res->start = start;
  58        res->end = start + len - 1;
  59        res->flags = acpi_dev_memresource_flags(len, write_protect, false);
  60}
  61
  62/**
  63 * acpi_dev_resource_memory - Extract ACPI memory resource information.
  64 * @ares: Input ACPI resource object.
  65 * @res: Output generic resource object.
  66 *
  67 * Check if the given ACPI resource object represents a memory resource and
  68 * if that's the case, use the information in it to populate the generic
  69 * resource object pointed to by @res.
  70 */
  71bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
  72{
  73        struct acpi_resource_memory24 *memory24;
  74        struct acpi_resource_memory32 *memory32;
  75        struct acpi_resource_fixed_memory32 *fixed_memory32;
  76
  77        switch (ares->type) {
  78        case ACPI_RESOURCE_TYPE_MEMORY24:
  79                memory24 = &ares->data.memory24;
  80                acpi_dev_get_memresource(res, memory24->minimum,
  81                                         memory24->address_length,
  82                                         memory24->write_protect);
  83                break;
  84        case ACPI_RESOURCE_TYPE_MEMORY32:
  85                memory32 = &ares->data.memory32;
  86                acpi_dev_get_memresource(res, memory32->minimum,
  87                                         memory32->address_length,
  88                                         memory32->write_protect);
  89                break;
  90        case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
  91                fixed_memory32 = &ares->data.fixed_memory32;
  92                acpi_dev_get_memresource(res, fixed_memory32->address,
  93                                         fixed_memory32->address_length,
  94                                         fixed_memory32->write_protect);
  95                break;
  96        default:
  97                return false;
  98        }
  99        return true;
 100}
 101EXPORT_SYMBOL_GPL(acpi_dev_resource_memory);
 102
 103static unsigned int acpi_dev_ioresource_flags(u64 start, u64 end, u8 io_decode,
 104                                              bool window)
 105{
 106        int flags = IORESOURCE_IO;
 107
 108        if (io_decode == ACPI_DECODE_16)
 109                flags |= IORESOURCE_IO_16BIT_ADDR;
 110
 111        if (start > end || end >= 0x10003)
 112                flags |= IORESOURCE_DISABLED;
 113
 114        if (window)
 115                flags |= IORESOURCE_WINDOW;
 116
 117        return flags;
 118}
 119
 120static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len,
 121                                    u8 io_decode)
 122{
 123        u64 end = start + len - 1;
 124
 125        res->start = start;
 126        res->end = end;
 127        res->flags = acpi_dev_ioresource_flags(start, end, io_decode, false);
 128}
 129
 130/**
 131 * acpi_dev_resource_io - Extract ACPI I/O resource information.
 132 * @ares: Input ACPI resource object.
 133 * @res: Output generic resource object.
 134 *
 135 * Check if the given ACPI resource object represents an I/O resource and
 136 * if that's the case, use the information in it to populate the generic
 137 * resource object pointed to by @res.
 138 */
 139bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res)
 140{
 141        struct acpi_resource_io *io;
 142        struct acpi_resource_fixed_io *fixed_io;
 143
 144        switch (ares->type) {
 145        case ACPI_RESOURCE_TYPE_IO:
 146                io = &ares->data.io;
 147                acpi_dev_get_ioresource(res, io->minimum,
 148                                        io->address_length,
 149                                        io->io_decode);
 150                break;
 151        case ACPI_RESOURCE_TYPE_FIXED_IO:
 152                fixed_io = &ares->data.fixed_io;
 153                acpi_dev_get_ioresource(res, fixed_io->address,
 154                                        fixed_io->address_length,
 155                                        ACPI_DECODE_10);
 156                break;
 157        default:
 158                return false;
 159        }
 160        return true;
 161}
 162EXPORT_SYMBOL_GPL(acpi_dev_resource_io);
 163
 164/**
 165 * acpi_dev_resource_address_space - Extract ACPI address space information.
 166 * @ares: Input ACPI resource object.
 167 * @res: Output generic resource object.
 168 *
 169 * Check if the given ACPI resource object represents an address space resource
 170 * and if that's the case, use the information in it to populate the generic
 171 * resource object pointed to by @res.
 172 */
 173bool acpi_dev_resource_address_space(struct acpi_resource *ares,
 174                                     struct resource *res)
 175{
 176        acpi_status status;
 177        struct acpi_resource_address64 addr;
 178        bool window;
 179        u64 len;
 180        u8 io_decode;
 181
 182        switch (ares->type) {
 183        case ACPI_RESOURCE_TYPE_ADDRESS16:
 184        case ACPI_RESOURCE_TYPE_ADDRESS32:
 185        case ACPI_RESOURCE_TYPE_ADDRESS64:
 186                break;
 187        default:
 188                return false;
 189        }
 190
 191        status = acpi_resource_to_address64(ares, &addr);
 192        if (ACPI_FAILURE(status))
 193                return true;
 194
 195        res->start = addr.minimum;
 196        res->end = addr.maximum;
 197        window = addr.producer_consumer == ACPI_PRODUCER;
 198
 199        switch(addr.resource_type) {
 200        case ACPI_MEMORY_RANGE:
 201                len = addr.maximum - addr.minimum + 1;
 202                res->flags = acpi_dev_memresource_flags(len,
 203                                                addr.info.mem.write_protect,
 204                                                window);
 205                break;
 206        case ACPI_IO_RANGE:
 207                io_decode = addr.granularity == 0xfff ?
 208                                ACPI_DECODE_10 : ACPI_DECODE_16;
 209                res->flags = acpi_dev_ioresource_flags(addr.minimum,
 210                                                       addr.maximum,
 211                                                       io_decode, window);
 212                break;
 213        case ACPI_BUS_NUMBER_RANGE:
 214                res->flags = IORESOURCE_BUS;
 215                break;
 216        default:
 217                res->flags = 0;
 218        }
 219
 220        return true;
 221}
 222EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space);
 223
 224/**
 225 * acpi_dev_resource_ext_address_space - Extract ACPI address space information.
 226 * @ares: Input ACPI resource object.
 227 * @res: Output generic resource object.
 228 *
 229 * Check if the given ACPI resource object represents an extended address space
 230 * resource and if that's the case, use the information in it to populate the
 231 * generic resource object pointed to by @res.
 232 */
 233bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares,
 234                                         struct resource *res)
 235{
 236        struct acpi_resource_extended_address64 *ext_addr;
 237        bool window;
 238        u64 len;
 239        u8 io_decode;
 240
 241        if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64)
 242                return false;
 243
 244        ext_addr = &ares->data.ext_address64;
 245
 246        res->start = ext_addr->minimum;
 247        res->end = ext_addr->maximum;
 248        window = ext_addr->producer_consumer == ACPI_PRODUCER;
 249
 250        switch(ext_addr->resource_type) {
 251        case ACPI_MEMORY_RANGE:
 252                len = ext_addr->maximum - ext_addr->minimum + 1;
 253                res->flags = acpi_dev_memresource_flags(len,
 254                                        ext_addr->info.mem.write_protect,
 255                                        window);
 256                break;
 257        case ACPI_IO_RANGE:
 258                io_decode = ext_addr->granularity == 0xfff ?
 259                                ACPI_DECODE_10 : ACPI_DECODE_16;
 260                res->flags = acpi_dev_ioresource_flags(ext_addr->minimum,
 261                                                       ext_addr->maximum,
 262                                                       io_decode, window);
 263                break;
 264        case ACPI_BUS_NUMBER_RANGE:
 265                res->flags = IORESOURCE_BUS;
 266                break;
 267        default:
 268                res->flags = 0;
 269        }
 270
 271        return true;
 272}
 273EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space);
 274
 275/**
 276 * acpi_dev_irq_flags - Determine IRQ resource flags.
 277 * @triggering: Triggering type as provided by ACPI.
 278 * @polarity: Interrupt polarity as provided by ACPI.
 279 * @shareable: Whether or not the interrupt is shareable.
 280 */
 281unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable)
 282{
 283        unsigned long flags;
 284
 285        if (triggering == ACPI_LEVEL_SENSITIVE)
 286                flags = polarity == ACPI_ACTIVE_LOW ?
 287                        IORESOURCE_IRQ_LOWLEVEL : IORESOURCE_IRQ_HIGHLEVEL;
 288        else
 289                flags = polarity == ACPI_ACTIVE_LOW ?
 290                        IORESOURCE_IRQ_LOWEDGE : IORESOURCE_IRQ_HIGHEDGE;
 291
 292        if (shareable == ACPI_SHARED)
 293                flags |= IORESOURCE_IRQ_SHAREABLE;
 294
 295        return flags | IORESOURCE_IRQ;
 296}
 297EXPORT_SYMBOL_GPL(acpi_dev_irq_flags);
 298
 299static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi)
 300{
 301        res->start = gsi;
 302        res->end = gsi;
 303        res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED;
 304}
 305
 306static void acpi_dev_get_irqresource(struct resource *res, u32 gsi,
 307                                     u8 triggering, u8 polarity, u8 shareable,
 308                                     bool legacy)
 309{
 310        int irq, p, t;
 311
 312        if (!valid_IRQ(gsi)) {
 313                acpi_dev_irqresource_disabled(res, gsi);
 314                return;
 315        }
 316
 317        /*
 318         * In IO-APIC mode, use overrided attribute. Two reasons:
 319         * 1. BIOS bug in DSDT
 320         * 2. BIOS uses IO-APIC mode Interrupt Source Override
 321         *
 322         * We do this only if we are dealing with IRQ() or IRQNoFlags()
 323         * resource (the legacy ISA resources). With modern ACPI 5 devices
 324         * using extended IRQ descriptors we take the IRQ configuration
 325         * from _CRS directly.
 326         */
 327        if (legacy && !acpi_get_override_irq(gsi, &t, &p)) {
 328                u8 trig = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
 329                u8 pol = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
 330
 331                if (triggering != trig || polarity != pol) {
 332                        pr_warning("ACPI: IRQ %d override to %s, %s\n", gsi,
 333                                   t ? "level" : "edge", p ? "low" : "high");
 334                        triggering = trig;
 335                        polarity = pol;
 336                }
 337        }
 338
 339        res->flags = acpi_dev_irq_flags(triggering, polarity, shareable);
 340        irq = acpi_register_gsi(NULL, gsi, triggering, polarity);
 341        if (irq >= 0) {
 342                res->start = irq;
 343                res->end = irq;
 344        } else {
 345                acpi_dev_irqresource_disabled(res, gsi);
 346        }
 347}
 348
 349/**
 350 * acpi_dev_resource_interrupt - Extract ACPI interrupt resource information.
 351 * @ares: Input ACPI resource object.
 352 * @index: Index into the array of GSIs represented by the resource.
 353 * @res: Output generic resource object.
 354 *
 355 * Check if the given ACPI resource object represents an interrupt resource
 356 * and @index does not exceed the resource's interrupt count (true is returned
 357 * in that case regardless of the results of the other checks)).  If that's the
 358 * case, register the GSI corresponding to @index from the array of interrupts
 359 * represented by the resource and populate the generic resource object pointed
 360 * to by @res accordingly.  If the registration of the GSI is not successful,
 361 * IORESOURCE_DISABLED will be set it that object's flags.
 362 */
 363bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
 364                                 struct resource *res)
 365{
 366        struct acpi_resource_irq *irq;
 367        struct acpi_resource_extended_irq *ext_irq;
 368
 369        switch (ares->type) {
 370        case ACPI_RESOURCE_TYPE_IRQ:
 371                /*
 372                 * Per spec, only one interrupt per descriptor is allowed in
 373                 * _CRS, but some firmware violates this, so parse them all.
 374                 */
 375                irq = &ares->data.irq;
 376                if (index >= irq->interrupt_count) {
 377                        acpi_dev_irqresource_disabled(res, 0);
 378                        return false;
 379                }
 380                acpi_dev_get_irqresource(res, irq->interrupts[index],
 381                                         irq->triggering, irq->polarity,
 382                                         irq->sharable, true);
 383                break;
 384        case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
 385                ext_irq = &ares->data.extended_irq;
 386                if (index >= ext_irq->interrupt_count) {
 387                        acpi_dev_irqresource_disabled(res, 0);
 388                        return false;
 389                }
 390                acpi_dev_get_irqresource(res, ext_irq->interrupts[index],
 391                                         ext_irq->triggering, ext_irq->polarity,
 392                                         ext_irq->sharable, false);
 393                break;
 394        default:
 395                return false;
 396        }
 397
 398        return true;
 399}
 400EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt);
 401
 402/**
 403 * acpi_dev_free_resource_list - Free resource from %acpi_dev_get_resources().
 404 * @list: The head of the resource list to free.
 405 */
 406void acpi_dev_free_resource_list(struct list_head *list)
 407{
 408        struct resource_list_entry *rentry, *re;
 409
 410        list_for_each_entry_safe(rentry, re, list, node) {
 411                list_del(&rentry->node);
 412                kfree(rentry);
 413        }
 414}
 415EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list);
 416
 417struct res_proc_context {
 418        struct list_head *list;
 419        int (*preproc)(struct acpi_resource *, void *);
 420        void *preproc_data;
 421        int count;
 422        int error;
 423};
 424
 425static acpi_status acpi_dev_new_resource_entry(struct resource *r,
 426                                               struct res_proc_context *c)
 427{
 428        struct resource_list_entry *rentry;
 429
 430        rentry = kmalloc(sizeof(*rentry), GFP_KERNEL);
 431        if (!rentry) {
 432                c->error = -ENOMEM;
 433                return AE_NO_MEMORY;
 434        }
 435        rentry->res = *r;
 436        list_add_tail(&rentry->node, c->list);
 437        c->count++;
 438        return AE_OK;
 439}
 440
 441static acpi_status acpi_dev_process_resource(struct acpi_resource *ares,
 442                                             void *context)
 443{
 444        struct res_proc_context *c = context;
 445        struct resource r;
 446        int i;
 447
 448        if (c->preproc) {
 449                int ret;
 450
 451                ret = c->preproc(ares, c->preproc_data);
 452                if (ret < 0) {
 453                        c->error = ret;
 454                        return AE_CTRL_TERMINATE;
 455                } else if (ret > 0) {
 456                        return AE_OK;
 457                }
 458        }
 459
 460        memset(&r, 0, sizeof(r));
 461
 462        if (acpi_dev_resource_memory(ares, &r)
 463            || acpi_dev_resource_io(ares, &r)
 464            || acpi_dev_resource_address_space(ares, &r)
 465            || acpi_dev_resource_ext_address_space(ares, &r))
 466                return acpi_dev_new_resource_entry(&r, c);
 467
 468        for (i = 0; acpi_dev_resource_interrupt(ares, i, &r); i++) {
 469                acpi_status status;
 470
 471                status = acpi_dev_new_resource_entry(&r, c);
 472                if (ACPI_FAILURE(status))
 473                        return status;
 474        }
 475
 476        return AE_OK;
 477}
 478
 479/**
 480 * acpi_dev_get_resources - Get current resources of a device.
 481 * @adev: ACPI device node to get the resources for.
 482 * @list: Head of the resultant list of resources (must be empty).
 483 * @preproc: The caller's preprocessing routine.
 484 * @preproc_data: Pointer passed to the caller's preprocessing routine.
 485 *
 486 * Evaluate the _CRS method for the given device node and process its output by
 487 * (1) executing the @preproc() rountine provided by the caller, passing the
 488 * resource pointer and @preproc_data to it as arguments, for each ACPI resource
 489 * returned and (2) converting all of the returned ACPI resources into struct
 490 * resource objects if possible.  If the return value of @preproc() in step (1)
 491 * is different from 0, step (2) is not applied to the given ACPI resource and
 492 * if that value is negative, the whole processing is aborted and that value is
 493 * returned as the final error code.
 494 *
 495 * The resultant struct resource objects are put on the list pointed to by
 496 * @list, that must be empty initially, as members of struct resource_list_entry
 497 * objects.  Callers of this routine should use %acpi_dev_free_resource_list() to
 498 * free that list.
 499 *
 500 * The number of resources in the output list is returned on success, an error
 501 * code reflecting the error condition is returned otherwise.
 502 */
 503int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list,
 504                           int (*preproc)(struct acpi_resource *, void *),
 505                           void *preproc_data)
 506{
 507        struct res_proc_context c;
 508        acpi_handle not_used;
 509        acpi_status status;
 510
 511        if (!adev || !adev->handle || !list_empty(list))
 512                return -EINVAL;
 513
 514        status = acpi_get_handle(adev->handle, METHOD_NAME__CRS, &not_used);
 515        if (ACPI_FAILURE(status))
 516                return 0;
 517
 518        c.list = list;
 519        c.preproc = preproc;
 520        c.preproc_data = preproc_data;
 521        c.count = 0;
 522        c.error = 0;
 523        status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
 524                                     acpi_dev_process_resource, &c);
 525        if (ACPI_FAILURE(status)) {
 526                acpi_dev_free_resource_list(list);
 527                return c.error ? c.error : -EIO;
 528        }
 529
 530        return c.count;
 531}
 532EXPORT_SYMBOL_GPL(acpi_dev_get_resources);
 533
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.