linux/drivers/acpi/resources/rscalc.c
<<
>>
Prefs
   1/*******************************************************************************
   2 *
   3 * Module Name: rscalc - Calculate stream and list lengths
   4 *
   5 ******************************************************************************/
   6
   7/*
   8 * Copyright (C) 2000 - 2008, Intel Corp.
   9 * All rights reserved.
  10 *
  11 * Redistribution and use in source and binary forms, with or without
  12 * modification, are permitted provided that the following conditions
  13 * are met:
  14 * 1. Redistributions of source code must retain the above copyright
  15 *    notice, this list of conditions, and the following disclaimer,
  16 *    without modification.
  17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  18 *    substantially similar to the "NO WARRANTY" disclaimer below
  19 *    ("Disclaimer") and any redistribution must be conditioned upon
  20 *    including a substantially similar Disclaimer requirement for further
  21 *    binary redistribution.
  22 * 3. Neither the names of the above-listed copyright holders nor the names
  23 *    of any contributors may be used to endorse or promote products derived
  24 *    from this software without specific prior written permission.
  25 *
  26 * Alternatively, this software may be distributed under the terms of the
  27 * GNU General Public License ("GPL") version 2 as published by the Free
  28 * Software Foundation.
  29 *
  30 * NO WARRANTY
  31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
  34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  41 * POSSIBILITY OF SUCH DAMAGES.
  42 */
  43
  44#include <acpi/acpi.h>
  45#include <acpi/acresrc.h>
  46#include <acpi/acnamesp.h>
  47
  48#define _COMPONENT          ACPI_RESOURCES
  49ACPI_MODULE_NAME("rscalc")
  50
  51/* Local prototypes */
  52static u8 acpi_rs_count_set_bits(u16 bit_field);
  53
  54static acpi_rs_length
  55acpi_rs_struct_option_length(struct acpi_resource_source *resource_source);
  56
  57static u32
  58acpi_rs_stream_option_length(u32 resource_length, u32 minimum_total_length);
  59
  60/*******************************************************************************
  61 *
  62 * FUNCTION:    acpi_rs_count_set_bits
  63 *
  64 * PARAMETERS:  bit_field       - Field in which to count bits
  65 *
  66 * RETURN:      Number of bits set within the field
  67 *
  68 * DESCRIPTION: Count the number of bits set in a resource field. Used for
  69 *              (Short descriptor) interrupt and DMA lists.
  70 *
  71 ******************************************************************************/
  72
  73static u8 acpi_rs_count_set_bits(u16 bit_field)
  74{
  75        u8 bits_set;
  76
  77        ACPI_FUNCTION_ENTRY();
  78
  79        for (bits_set = 0; bit_field; bits_set++) {
  80
  81                /* Zero the least significant bit that is set */
  82
  83                bit_field &= (u16) (bit_field - 1);
  84        }
  85
  86        return bits_set;
  87}
  88
  89/*******************************************************************************
  90 *
  91 * FUNCTION:    acpi_rs_struct_option_length
  92 *
  93 * PARAMETERS:  resource_source     - Pointer to optional descriptor field
  94 *
  95 * RETURN:      Status
  96 *
  97 * DESCRIPTION: Common code to handle optional resource_source_index and
  98 *              resource_source fields in some Large descriptors. Used during
  99 *              list-to-stream conversion
 100 *
 101 ******************************************************************************/
 102
 103static acpi_rs_length
 104acpi_rs_struct_option_length(struct acpi_resource_source *resource_source)
 105{
 106        ACPI_FUNCTION_ENTRY();
 107
 108        /*
 109         * If the resource_source string is valid, return the size of the string
 110         * (string_length includes the NULL terminator) plus the size of the
 111         * resource_source_index (1).
 112         */
 113        if (resource_source->string_ptr) {
 114                return ((acpi_rs_length) (resource_source->string_length + 1));
 115        }
 116
 117        return (0);
 118}
 119
 120/*******************************************************************************
 121 *
 122 * FUNCTION:    acpi_rs_stream_option_length
 123 *
 124 * PARAMETERS:  resource_length     - Length from the resource header
 125 *              minimum_total_length - Minimum length of this resource, before
 126 *                                    any optional fields. Includes header size
 127 *
 128 * RETURN:      Length of optional string (0 if no string present)
 129 *
 130 * DESCRIPTION: Common code to handle optional resource_source_index and
 131 *              resource_source fields in some Large descriptors. Used during
 132 *              stream-to-list conversion
 133 *
 134 ******************************************************************************/
 135
 136static u32
 137acpi_rs_stream_option_length(u32 resource_length,
 138                             u32 minimum_aml_resource_length)
 139{
 140        u32 string_length = 0;
 141
 142        ACPI_FUNCTION_ENTRY();
 143
 144        /*
 145         * The resource_source_index and resource_source are optional elements of some
 146         * Large-type resource descriptors.
 147         */
 148
 149        /*
 150         * If the length of the actual resource descriptor is greater than the ACPI
 151         * spec-defined minimum length, it means that a resource_source_index exists
 152         * and is followed by a (required) null terminated string. The string length
 153         * (including the null terminator) is the resource length minus the minimum
 154         * length, minus one byte for the resource_source_index itself.
 155         */
 156        if (resource_length > minimum_aml_resource_length) {
 157
 158                /* Compute the length of the optional string */
 159
 160                string_length =
 161                    resource_length - minimum_aml_resource_length - 1;
 162        }
 163
 164        /*
 165         * Round the length up to a multiple of the native word in order to
 166         * guarantee that the entire resource descriptor is native word aligned
 167         */
 168        return ((u32) ACPI_ROUND_UP_TO_NATIVE_WORD(string_length));
 169}
 170
 171/*******************************************************************************
 172 *
 173 * FUNCTION:    acpi_rs_get_aml_length
 174 *
 175 * PARAMETERS:  Resource            - Pointer to the resource linked list
 176 *              size_needed         - Where the required size is returned
 177 *
 178 * RETURN:      Status
 179 *
 180 * DESCRIPTION: Takes a linked list of internal resource descriptors and
 181 *              calculates the size buffer needed to hold the corresponding
 182 *              external resource byte stream.
 183 *
 184 ******************************************************************************/
 185
 186acpi_status
 187acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed)
 188{
 189        acpi_size aml_size_needed = 0;
 190        acpi_rs_length total_size;
 191
 192        ACPI_FUNCTION_TRACE(rs_get_aml_length);
 193
 194        /* Traverse entire list of internal resource descriptors */
 195
 196        while (resource) {
 197
 198                /* Validate the descriptor type */
 199
 200                if (resource->type > ACPI_RESOURCE_TYPE_MAX) {
 201                        return_ACPI_STATUS(AE_AML_INVALID_RESOURCE_TYPE);
 202                }
 203
 204                /* Get the base size of the (external stream) resource descriptor */
 205
 206                total_size = acpi_gbl_aml_resource_sizes[resource->type];
 207
 208                /*
 209                 * Augment the base size for descriptors with optional and/or
 210                 * variable-length fields
 211                 */
 212                switch (resource->type) {
 213                case ACPI_RESOURCE_TYPE_IRQ:
 214
 215                        /* Length can be 3 or 2 */
 216
 217                        if (resource->data.irq.descriptor_length == 2) {
 218                                total_size--;
 219                        }
 220                        break;
 221
 222                case ACPI_RESOURCE_TYPE_START_DEPENDENT:
 223
 224                        /* Length can be 1 or 0 */
 225
 226                        if (resource->data.irq.descriptor_length == 0) {
 227                                total_size--;
 228                        }
 229                        break;
 230
 231                case ACPI_RESOURCE_TYPE_VENDOR:
 232                        /*
 233                         * Vendor Defined Resource:
 234                         * For a Vendor Specific resource, if the Length is between 1 and 7
 235                         * it will be created as a Small Resource data type, otherwise it
 236                         * is a Large Resource data type.
 237                         */
 238                        if (resource->data.vendor.byte_length > 7) {
 239
 240                                /* Base size of a Large resource descriptor */
 241
 242                                total_size =
 243                                    sizeof(struct aml_resource_large_header);
 244                        }
 245
 246                        /* Add the size of the vendor-specific data */
 247
 248                        total_size = (acpi_rs_length)
 249                            (total_size + resource->data.vendor.byte_length);
 250                        break;
 251
 252                case ACPI_RESOURCE_TYPE_END_TAG:
 253                        /*
 254                         * End Tag:
 255                         * We are done -- return the accumulated total size.
 256                         */
 257                        *size_needed = aml_size_needed + total_size;
 258
 259                        /* Normal exit */
 260
 261                        return_ACPI_STATUS(AE_OK);
 262
 263                case ACPI_RESOURCE_TYPE_ADDRESS16:
 264                        /*
 265                         * 16-Bit Address Resource:
 266                         * Add the size of the optional resource_source info
 267                         */
 268                        total_size = (acpi_rs_length)
 269                            (total_size +
 270                             acpi_rs_struct_option_length(&resource->data.
 271                                                          address16.
 272                                                          resource_source));
 273                        break;
 274
 275                case ACPI_RESOURCE_TYPE_ADDRESS32:
 276                        /*
 277                         * 32-Bit Address Resource:
 278                         * Add the size of the optional resource_source info
 279                         */
 280                        total_size = (acpi_rs_length)
 281                            (total_size +
 282                             acpi_rs_struct_option_length(&resource->data.
 283                                                          address32.
 284                                                          resource_source));
 285                        break;
 286
 287                case ACPI_RESOURCE_TYPE_ADDRESS64:
 288                        /*
 289                         * 64-Bit Address Resource:
 290                         * Add the size of the optional resource_source info
 291                         */
 292                        total_size = (acpi_rs_length)
 293                            (total_size +
 294                             acpi_rs_struct_option_length(&resource->data.
 295                                                          address64.
 296                                                          resource_source));
 297                        break;
 298
 299                case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
 300                        /*
 301                         * Extended IRQ Resource:
 302                         * Add the size of each additional optional interrupt beyond the
 303                         * required 1 (4 bytes for each u32 interrupt number)
 304                         */
 305                        total_size = (acpi_rs_length)
 306                            (total_size +
 307                             ((resource->data.extended_irq.interrupt_count -
 308                               1) * 4) +
 309                             /* Add the size of the optional resource_source info */
 310                             acpi_rs_struct_option_length(&resource->data.
 311                                                          extended_irq.
 312                                                          resource_source));
 313                        break;
 314
 315                default:
 316                        break;
 317                }
 318
 319                /* Update the total */
 320
 321                aml_size_needed += total_size;
 322
 323                /* Point to the next object */
 324
 325                resource =
 326                    ACPI_ADD_PTR(struct acpi_resource, resource,
 327                                 resource->length);
 328        }
 329
 330        /* Did not find an end_tag resource descriptor */
 331
 332        return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
 333}
 334
 335/*******************************************************************************
 336 *
 337 * FUNCTION:    acpi_rs_get_list_length
 338 *
 339 * PARAMETERS:  aml_buffer          - Pointer to the resource byte stream
 340 *              aml_buffer_length   - Size of aml_buffer
 341 *              size_needed         - Where the size needed is returned
 342 *
 343 * RETURN:      Status
 344 *
 345 * DESCRIPTION: Takes an external resource byte stream and calculates the size
 346 *              buffer needed to hold the corresponding internal resource
 347 *              descriptor linked list.
 348 *
 349 ******************************************************************************/
 350
 351acpi_status
 352acpi_rs_get_list_length(u8 * aml_buffer,
 353                        u32 aml_buffer_length, acpi_size * size_needed)
 354{
 355        acpi_status status;
 356        u8 *end_aml;
 357        u8 *buffer;
 358        u32 buffer_size;
 359        u16 temp16;
 360        u16 resource_length;
 361        u32 extra_struct_bytes;
 362        u8 resource_index;
 363        u8 minimum_aml_resource_length;
 364
 365        ACPI_FUNCTION_TRACE(rs_get_list_length);
 366
 367        *size_needed = 0;
 368        end_aml = aml_buffer + aml_buffer_length;
 369
 370        /* Walk the list of AML resource descriptors */
 371
 372        while (aml_buffer < end_aml) {
 373
 374                /* Validate the Resource Type and Resource Length */
 375
 376                status = acpi_ut_validate_resource(aml_buffer, &resource_index);
 377                if (ACPI_FAILURE(status)) {
 378                        return_ACPI_STATUS(status);
 379                }
 380
 381                /* Get the resource length and base (minimum) AML size */
 382
 383                resource_length = acpi_ut_get_resource_length(aml_buffer);
 384                minimum_aml_resource_length =
 385                    acpi_gbl_resource_aml_sizes[resource_index];
 386
 387                /*
 388                 * Augment the size for descriptors with optional
 389                 * and/or variable length fields
 390                 */
 391                extra_struct_bytes = 0;
 392                buffer =
 393                    aml_buffer + acpi_ut_get_resource_header_length(aml_buffer);
 394
 395                switch (acpi_ut_get_resource_type(aml_buffer)) {
 396                case ACPI_RESOURCE_NAME_IRQ:
 397                        /*
 398                         * IRQ Resource:
 399                         * Get the number of bits set in the 16-bit IRQ mask
 400                         */
 401                        ACPI_MOVE_16_TO_16(&temp16, buffer);
 402                        extra_struct_bytes = acpi_rs_count_set_bits(temp16);
 403                        break;
 404
 405                case ACPI_RESOURCE_NAME_DMA:
 406                        /*
 407                         * DMA Resource:
 408                         * Get the number of bits set in the 8-bit DMA mask
 409                         */
 410                        extra_struct_bytes = acpi_rs_count_set_bits(*buffer);
 411                        break;
 412
 413                case ACPI_RESOURCE_NAME_VENDOR_SMALL:
 414                case ACPI_RESOURCE_NAME_VENDOR_LARGE:
 415                        /*
 416                         * Vendor Resource:
 417                         * Get the number of vendor data bytes
 418                         */
 419                        extra_struct_bytes = resource_length;
 420                        break;
 421
 422                case ACPI_RESOURCE_NAME_END_TAG:
 423                        /*
 424                         * End Tag:
 425                         * This is the normal exit, add size of end_tag
 426                         */
 427                        *size_needed += ACPI_RS_SIZE_MIN;
 428                        return_ACPI_STATUS(AE_OK);
 429
 430                case ACPI_RESOURCE_NAME_ADDRESS32:
 431                case ACPI_RESOURCE_NAME_ADDRESS16:
 432                case ACPI_RESOURCE_NAME_ADDRESS64:
 433                        /*
 434                         * Address Resource:
 435                         * Add the size of the optional resource_source
 436                         */
 437                        extra_struct_bytes =
 438                            acpi_rs_stream_option_length(resource_length,
 439                                                         minimum_aml_resource_length);
 440                        break;
 441
 442                case ACPI_RESOURCE_NAME_EXTENDED_IRQ:
 443                        /*
 444                         * Extended IRQ Resource:
 445                         * Using the interrupt_table_length, add 4 bytes for each additional
 446                         * interrupt. Note: at least one interrupt is required and is
 447                         * included in the minimum descriptor size (reason for the -1)
 448                         */
 449                        extra_struct_bytes = (buffer[1] - 1) * sizeof(u32);
 450
 451                        /* Add the size of the optional resource_source */
 452
 453                        extra_struct_bytes +=
 454                            acpi_rs_stream_option_length(resource_length -
 455                                                         extra_struct_bytes,
 456                                                         minimum_aml_resource_length);
 457                        break;
 458
 459                default:
 460                        break;
 461                }
 462
 463                /*
 464                 * Update the required buffer size for the internal descriptor structs
 465                 *
 466                 * Important: Round the size up for the appropriate alignment. This
 467                 * is a requirement on IA64.
 468                 */
 469                buffer_size = acpi_gbl_resource_struct_sizes[resource_index] +
 470                    extra_struct_bytes;
 471                buffer_size = (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(buffer_size);
 472
 473                *size_needed += buffer_size;
 474
 475                ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
 476                                  "Type %.2X, AmlLength %.2X InternalLength %.2X\n",
 477                                  acpi_ut_get_resource_type(aml_buffer),
 478                                  acpi_ut_get_descriptor_length(aml_buffer),
 479                                  buffer_size));
 480
 481                /*
 482                 * Point to the next resource within the AML stream using the length
 483                 * contained in the resource descriptor header
 484                 */
 485                aml_buffer += acpi_ut_get_descriptor_length(aml_buffer);
 486        }
 487
 488        /* Did not find an end_tag resource descriptor */
 489
 490        return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
 491}
 492
 493/*******************************************************************************
 494 *
 495 * FUNCTION:    acpi_rs_get_pci_routing_table_length
 496 *
 497 * PARAMETERS:  package_object          - Pointer to the package object
 498 *              buffer_size_needed      - u32 pointer of the size buffer
 499 *                                        needed to properly return the
 500 *                                        parsed data
 501 *
 502 * RETURN:      Status
 503 *
 504 * DESCRIPTION: Given a package representing a PCI routing table, this
 505 *              calculates the size of the corresponding linked list of
 506 *              descriptions.
 507 *
 508 ******************************************************************************/
 509
 510acpi_status
 511acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
 512                                     acpi_size * buffer_size_needed)
 513{
 514        u32 number_of_elements;
 515        acpi_size temp_size_needed = 0;
 516        union acpi_operand_object **top_object_list;
 517        u32 index;
 518        union acpi_operand_object *package_element;
 519        union acpi_operand_object **sub_object_list;
 520        u8 name_found;
 521        u32 table_index;
 522
 523        ACPI_FUNCTION_TRACE(rs_get_pci_routing_table_length);
 524
 525        number_of_elements = package_object->package.count;
 526
 527        /*
 528         * Calculate the size of the return buffer.
 529         * The base size is the number of elements * the sizes of the
 530         * structures.  Additional space for the strings is added below.
 531         * The minus one is to subtract the size of the u8 Source[1]
 532         * member because it is added below.
 533         *
 534         * But each PRT_ENTRY structure has a pointer to a string and
 535         * the size of that string must be found.
 536         */
 537        top_object_list = package_object->package.elements;
 538
 539        for (index = 0; index < number_of_elements; index++) {
 540
 541                /* Dereference the sub-package */
 542
 543                package_element = *top_object_list;
 544
 545                /*
 546                 * The sub_object_list will now point to an array of the
 547                 * four IRQ elements: Address, Pin, Source and source_index
 548                 */
 549                sub_object_list = package_element->package.elements;
 550
 551                /* Scan the irq_table_elements for the Source Name String */
 552
 553                name_found = FALSE;
 554
 555                for (table_index = 0; table_index < 4 && !name_found;
 556                     table_index++) {
 557                        if (*sub_object_list && /* Null object allowed */
 558                            ((ACPI_TYPE_STRING ==
 559                              ACPI_GET_OBJECT_TYPE(*sub_object_list)) ||
 560                             ((ACPI_TYPE_LOCAL_REFERENCE ==
 561                               ACPI_GET_OBJECT_TYPE(*sub_object_list)) &&
 562                              ((*sub_object_list)->reference.class ==
 563                               ACPI_REFCLASS_NAME)))) {
 564                                name_found = TRUE;
 565                        } else {
 566                                /* Look at the next element */
 567
 568                                sub_object_list++;
 569                        }
 570                }
 571
 572                temp_size_needed += (sizeof(struct acpi_pci_routing_table) - 4);
 573
 574                /* Was a String type found? */
 575
 576                if (name_found) {
 577                        if (ACPI_GET_OBJECT_TYPE(*sub_object_list) ==
 578                            ACPI_TYPE_STRING) {
 579                                /*
 580                                 * The length String.Length field does not include the
 581                                 * terminating NULL, add 1
 582                                 */
 583                                temp_size_needed += ((acpi_size)
 584                                                     (*sub_object_list)->string.
 585                                                     length + 1);
 586                        } else {
 587                                temp_size_needed +=
 588                                    acpi_ns_get_pathname_length((*sub_object_list)->reference.node);
 589                                if (!temp_size_needed) {
 590                                        return_ACPI_STATUS(AE_BAD_PARAMETER);
 591                                }
 592                        }
 593                } else {
 594                        /*
 595                         * If no name was found, then this is a NULL, which is
 596                         * translated as a u32 zero.
 597                         */
 598                        temp_size_needed += sizeof(u32);
 599                }
 600
 601                /* Round up the size since each element must be aligned */
 602
 603                temp_size_needed = ACPI_ROUND_UP_TO_64BIT(temp_size_needed);
 604
 605                /* Point to the next union acpi_operand_object */
 606
 607                top_object_list++;
 608        }
 609
 610        /*
 611         * Add an extra element to the end of the list, essentially a
 612         * NULL terminator
 613         */
 614        *buffer_size_needed =
 615            temp_size_needed + sizeof(struct acpi_pci_routing_table);
 616        return_ACPI_STATUS(AE_OK);
 617}
 618
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.