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{
 309        int irq, p, t;
 310
 311        if (!valid_IRQ(gsi)) {
 312                acpi_dev_irqresource_disabled(res, gsi);
 313                return;
 314        }
 315
 316        /*
 317         * In IO-APIC mode, use overrided attribute. Two reasons:
 318         * 1. BIOS bug in DSDT
 319         * 2. BIOS uses IO-APIC mode Interrupt Source Override
 320         */
 321        if (!acpi_get_override_irq(gsi, &t, &p)) {
 322                u8 trig = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
 323                u8 pol = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
 324
 325                if (triggering != trig || polarity != pol) {
 326                        pr_warning("ACPI: IRQ %d override to %s, %s\n", gsi,
 327                                   t ? "edge" : "level", p ? "low" : "high");
 328                        triggering = trig;
 329                        polarity = pol;
 330                }
 331        }
 332
 333        res->flags = acpi_dev_irq_flags(triggering, polarity, shareable);
 334        irq = acpi_register_gsi(NULL, gsi, triggering, polarity);
 335        if (irq >= 0) {
 336                res->start = irq;
 337                res->end = irq;
 338        } else {
 339                acpi_dev_irqresource_disabled(res, gsi);
 340        }
 341}
 342
 343/**
 344 * acpi_dev_resource_interrupt - Extract ACPI interrupt resource information.
 345 * @ares: Input ACPI resource object.
 346 * @index: Index into the array of GSIs represented by the resource.
 347 * @res: Output generic resource object.
 348 *
 349 * Check if the given ACPI resource object represents an interrupt resource
 350 * and @index does not exceed the resource's interrupt count (true is returned
 351 * in that case regardless of the results of the other checks)).  If that's the
 352 * case, register the GSI corresponding to @index from the array of interrupts
 353 * represented by the resource and populate the generic resource object pointed
 354 * to by @res accordingly.  If the registration of the GSI is not successful,
 355 * IORESOURCE_DISABLED will be set it that object's flags.
 356 */
 357bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
 358                                 struct resource *res)
 359{
 360        struct acpi_resource_irq *irq;
 361        struct acpi_resource_extended_irq *ext_irq;
 362
 363        switch (ares->type) {
 364        case ACPI_RESOURCE_TYPE_IRQ:
 365                /*
 366                 * Per spec, only one interrupt per descriptor is allowed in
 367                 * _CRS, but some firmware violates this, so parse them all.
 368                 */
 369                irq = &ares->data.irq;
 370                if (index >= irq->interrupt_count) {
 371                        acpi_dev_irqresource_disabled(res, 0);
 372                        return false;
 373                }
 374                acpi_dev_get_irqresource(res, irq->interrupts[index],
 375                                         irq->triggering, irq->polarity,
 376                                         irq->sharable);
 377                break;
 378        case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
 379                ext_irq = &ares->data.extended_irq;
 380                if (index >= ext_irq->interrupt_count) {
 381                        acpi_dev_irqresource_disabled(res, 0);
 382                        return false;
 383                }
 384                acpi_dev_get_irqresource(res, ext_irq->interrupts[index],
 385                                         ext_irq->triggering, ext_irq->polarity,
 386                                         ext_irq->sharable);
 387                break;
 388        default:
 389                return false;
 390        }
 391
 392        return true;
 393}
 394EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt);
 395
 396/**
 397 * acpi_dev_free_resource_list - Free resource from %acpi_dev_get_resources().
 398 * @list: The head of the resource list to free.
 399 */
 400void acpi_dev_free_resource_list(struct list_head *list)
 401{
 402        struct resource_list_entry *rentry, *re;
 403
 404        list_for_each_entry_safe(rentry, re, list, node) {
 405                list_del(&rentry->node);
 406                kfree(rentry);
 407        }
 408}
 409EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list);
 410
 411struct res_proc_context {
 412        struct list_head *list;
 413        int (*preproc)(struct acpi_resource *, void *);
 414        void *preproc_data;
 415        int count;
 416        int error;
 417};
 418
 419static acpi_status acpi_dev_new_resource_entry(struct resource *r,
 420                                               struct res_proc_context *c)
 421{
 422        struct resource_list_entry *rentry;
 423
 424        rentry = kmalloc(sizeof(*rentry), GFP_KERNEL);
 425        if (!rentry) {
 426                c->error = -ENOMEM;
 427                return AE_NO_MEMORY;
 428        }
 429        rentry->res = *r;
 430        list_add_tail(&rentry->node, c->list);
 431        c->count++;
 432        return AE_OK;
 433}
 434
 435static acpi_status acpi_dev_process_resource(struct acpi_resource *ares,
 436                                             void *context)
 437{
 438        struct res_proc_context *c = context;
 439        struct resource r;
 440        int i;
 441
 442        if (c->preproc) {
 443                int ret;
 444
 445                ret = c->preproc(ares, c->preproc_data);
 446                if (ret < 0) {
 447                        c->error = ret;
 448                        return AE_CTRL_TERMINATE;
 449                } else if (ret > 0) {
 450                        return AE_OK;
 451                }
 452        }
 453
 454        memset(&r, 0, sizeof(r));
 455
 456        if (acpi_dev_resource_memory(ares, &r)
 457            || acpi_dev_resource_io(ares, &r)
 458            || acpi_dev_resource_address_space(ares, &r)
 459            || acpi_dev_resource_ext_address_space(ares, &r))
 460                return acpi_dev_new_resource_entry(&r, c);
 461
 462        for (i = 0; acpi_dev_resource_interrupt(ares, i, &r); i++) {
 463                acpi_status status;
 464
 465                status = acpi_dev_new_resource_entry(&r, c);
 466                if (ACPI_FAILURE(status))
 467                        return status;
 468        }
 469
 470        return AE_OK;
 471}
 472
 473/**
 474 * acpi_dev_get_resources - Get current resources of a device.
 475 * @adev: ACPI device node to get the resources for.
 476 * @list: Head of the resultant list of resources (must be empty).
 477 * @preproc: The caller's preprocessing routine.
 478 * @preproc_data: Pointer passed to the caller's preprocessing routine.
 479 *
 480 * Evaluate the _CRS method for the given device node and process its output by
 481 * (1) executing the @preproc() rountine provided by the caller, passing the
 482 * resource pointer and @preproc_data to it as arguments, for each ACPI resource
 483 * returned and (2) converting all of the returned ACPI resources into struct
 484 * resource objects if possible.  If the return value of @preproc() in step (1)
 485 * is different from 0, step (2) is not applied to the given ACPI resource and
 486 * if that value is negative, the whole processing is aborted and that value is
 487 * returned as the final error code.
 488 *
 489 * The resultant struct resource objects are put on the list pointed to by
 490 * @list, that must be empty initially, as members of struct resource_list_entry
 491 * objects.  Callers of this routine should use %acpi_dev_free_resource_list() to
 492 * free that list.
 493 *
 494 * The number of resources in the output list is returned on success, an error
 495 * code reflecting the error condition is returned otherwise.
 496 */
 497int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list,
 498                           int (*preproc)(struct acpi_resource *, void *),
 499                           void *preproc_data)
 500{
 501        struct res_proc_context c;
 502        acpi_handle not_used;
 503        acpi_status status;
 504
 505        if (!adev || !adev->handle || !list_empty(list))
 506                return -EINVAL;
 507
 508        status = acpi_get_handle(adev->handle, METHOD_NAME__CRS, &not_used);
 509        if (ACPI_FAILURE(status))
 510                return 0;
 511
 512        c.list = list;
 513        c.preproc = preproc;
 514        c.preproc_data = preproc_data;
 515        c.count = 0;
 516        c.error = 0;
 517        status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
 518                                     acpi_dev_process_resource, &c);
 519        if (ACPI_FAILURE(status)) {
 520                acpi_dev_free_resource_list(list);
 521                return c.error ? c.error : -EIO;
 522        }
 523
 524        return c.count;
 525}
 526EXPORT_SYMBOL_GPL(acpi_dev_get_resources);
 527
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.