linux/drivers/acpi/acpica/rscalc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/*******************************************************************************
   3 *
   4 * Module Name: rscalc - Calculate stream and list lengths
   5 *
   6 ******************************************************************************/
   7
   8#include <acpi/acpi.h>
   9#include "accommon.h"
  10#include "acresrc.h"
  11#include "acnamesp.h"
  12
  13#define _COMPONENT          ACPI_RESOURCES
  14ACPI_MODULE_NAME("rscalc")
  15
  16/* Local prototypes */
  17static u8 acpi_rs_count_set_bits(u16 bit_field);
  18
  19static acpi_rs_length
  20acpi_rs_struct_option_length(struct acpi_resource_source *resource_source);
  21
  22static u32
  23acpi_rs_stream_option_length(u32 resource_length, u32 minimum_total_length);
  24
  25/*******************************************************************************
  26 *
  27 * FUNCTION:    acpi_rs_count_set_bits
  28 *
  29 * PARAMETERS:  bit_field       - Field in which to count bits
  30 *
  31 * RETURN:      Number of bits set within the field
  32 *
  33 * DESCRIPTION: Count the number of bits set in a resource field. Used for
  34 *              (Short descriptor) interrupt and DMA lists.
  35 *
  36 ******************************************************************************/
  37
  38static u8 acpi_rs_count_set_bits(u16 bit_field)
  39{
  40        u8 bits_set;
  41
  42        ACPI_FUNCTION_ENTRY();
  43
  44        for (bits_set = 0; bit_field; bits_set++) {
  45
  46                /* Zero the least significant bit that is set */
  47
  48                bit_field &= (u16) (bit_field - 1);
  49        }
  50
  51        return (bits_set);
  52}
  53
  54/*******************************************************************************
  55 *
  56 * FUNCTION:    acpi_rs_struct_option_length
  57 *
  58 * PARAMETERS:  resource_source     - Pointer to optional descriptor field
  59 *
  60 * RETURN:      Status
  61 *
  62 * DESCRIPTION: Common code to handle optional resource_source_index and
  63 *              resource_source fields in some Large descriptors. Used during
  64 *              list-to-stream conversion
  65 *
  66 ******************************************************************************/
  67
  68static acpi_rs_length
  69acpi_rs_struct_option_length(struct acpi_resource_source *resource_source)
  70{
  71        ACPI_FUNCTION_ENTRY();
  72
  73        /*
  74         * If the resource_source string is valid, return the size of the string
  75         * (string_length includes the NULL terminator) plus the size of the
  76         * resource_source_index (1).
  77         */
  78        if (resource_source->string_ptr) {
  79                return ((acpi_rs_length)(resource_source->string_length + 1));
  80        }
  81
  82        return (0);
  83}
  84
  85/*******************************************************************************
  86 *
  87 * FUNCTION:    acpi_rs_stream_option_length
  88 *
  89 * PARAMETERS:  resource_length     - Length from the resource header
  90 *              minimum_total_length - Minimum length of this resource, before
  91 *                                    any optional fields. Includes header size
  92 *
  93 * RETURN:      Length of optional string (0 if no string present)
  94 *
  95 * DESCRIPTION: Common code to handle optional resource_source_index and
  96 *              resource_source fields in some Large descriptors. Used during
  97 *              stream-to-list conversion
  98 *
  99 ******************************************************************************/
 100
 101static u32
 102acpi_rs_stream_option_length(u32 resource_length,
 103                             u32 minimum_aml_resource_length)
 104{
 105        u32 string_length = 0;
 106
 107        ACPI_FUNCTION_ENTRY();
 108
 109        /*
 110         * The resource_source_index and resource_source are optional elements of
 111         * some Large-type resource descriptors.
 112         */
 113
 114        /*
 115         * If the length of the actual resource descriptor is greater than the
 116         * ACPI spec-defined minimum length, it means that a resource_source_index
 117         * exists and is followed by a (required) null terminated string. The
 118         * string length (including the null terminator) is the resource length
 119         * minus the minimum length, minus one byte for the resource_source_index
 120         * itself.
 121         */
 122        if (resource_length > minimum_aml_resource_length) {
 123
 124                /* Compute the length of the optional string */
 125
 126                string_length =
 127                    resource_length - minimum_aml_resource_length - 1;
 128        }
 129
 130        /*
 131         * Round the length up to a multiple of the native word in order to
 132         * guarantee that the entire resource descriptor is native word aligned
 133         */
 134        return ((u32) ACPI_ROUND_UP_TO_NATIVE_WORD(string_length));
 135}
 136
 137/*******************************************************************************
 138 *
 139 * FUNCTION:    acpi_rs_get_aml_length
 140 *
 141 * PARAMETERS:  resource            - Pointer to the resource linked list
 142 *              resource_list_size  - Size of the resource linked list
 143 *              size_needed         - Where the required size is returned
 144 *
 145 * RETURN:      Status
 146 *
 147 * DESCRIPTION: Takes a linked list of internal resource descriptors and
 148 *              calculates the size buffer needed to hold the corresponding
 149 *              external resource byte stream.
 150 *
 151 ******************************************************************************/
 152
 153acpi_status
 154acpi_rs_get_aml_length(struct acpi_resource *resource,
 155                       acpi_size resource_list_size, acpi_size *size_needed)
 156{
 157        acpi_size aml_size_needed = 0;
 158        struct acpi_resource *resource_end;
 159        acpi_rs_length total_size;
 160
 161        ACPI_FUNCTION_TRACE(rs_get_aml_length);
 162
 163        /* Traverse entire list of internal resource descriptors */
 164
 165        resource_end =
 166            ACPI_ADD_PTR(struct acpi_resource, resource, resource_list_size);
 167        while (resource < resource_end) {
 168
 169                /* Validate the descriptor type */
 170
 171                if (resource->type > ACPI_RESOURCE_TYPE_MAX) {
 172                        return_ACPI_STATUS(AE_AML_INVALID_RESOURCE_TYPE);
 173                }
 174
 175                /* Sanity check the length. It must not be zero, or we loop forever */
 176
 177                if (!resource->length) {
 178                        return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH);
 179                }
 180
 181                /* Get the base size of the (external stream) resource descriptor */
 182
 183                total_size = acpi_gbl_aml_resource_sizes[resource->type];
 184
 185                /*
 186                 * Augment the base size for descriptors with optional and/or
 187                 * variable-length fields
 188                 */
 189                switch (resource->type) {
 190                case ACPI_RESOURCE_TYPE_IRQ:
 191
 192                        /* Length can be 3 or 2 */
 193
 194                        if (resource->data.irq.descriptor_length == 2) {
 195                                total_size--;
 196                        }
 197                        break;
 198
 199                case ACPI_RESOURCE_TYPE_START_DEPENDENT:
 200
 201                        /* Length can be 1 or 0 */
 202
 203                        if (resource->data.irq.descriptor_length == 0) {
 204                                total_size--;
 205                        }
 206                        break;
 207
 208                case ACPI_RESOURCE_TYPE_VENDOR:
 209                        /*
 210                         * Vendor Defined Resource:
 211                         * For a Vendor Specific resource, if the Length is between 1 and 7
 212                         * it will be created as a Small Resource data type, otherwise it
 213                         * is a Large Resource data type.
 214                         */
 215                        if (resource->data.vendor.byte_length > 7) {
 216
 217                                /* Base size of a Large resource descriptor */
 218
 219                                total_size =
 220                                    sizeof(struct aml_resource_large_header);
 221                        }
 222
 223                        /* Add the size of the vendor-specific data */
 224
 225                        total_size = (acpi_rs_length)
 226                            (total_size + resource->data.vendor.byte_length);
 227                        break;
 228
 229                case ACPI_RESOURCE_TYPE_END_TAG:
 230                        /*
 231                         * End Tag:
 232                         * We are done -- return the accumulated total size.
 233                         */
 234                        *size_needed = aml_size_needed + total_size;
 235
 236                        /* Normal exit */
 237
 238                        return_ACPI_STATUS(AE_OK);
 239
 240                case ACPI_RESOURCE_TYPE_ADDRESS16:
 241                        /*
 242                         * 16-Bit Address Resource:
 243                         * Add the size of the optional resource_source info
 244                         */
 245                        total_size = (acpi_rs_length)(total_size +
 246                                                      acpi_rs_struct_option_length
 247                                                      (&resource->data.
 248                                                       address16.
 249                                                       resource_source));
 250                        break;
 251
 252                case ACPI_RESOURCE_TYPE_ADDRESS32:
 253                        /*
 254                         * 32-Bit Address Resource:
 255                         * Add the size of the optional resource_source info
 256                         */
 257                        total_size = (acpi_rs_length)(total_size +
 258                                                      acpi_rs_struct_option_length
 259                                                      (&resource->data.
 260                                                       address32.
 261                                                       resource_source));
 262                        break;
 263
 264                case ACPI_RESOURCE_TYPE_ADDRESS64:
 265                        /*
 266                         * 64-Bit Address Resource:
 267                         * Add the size of the optional resource_source info
 268                         */
 269                        total_size = (acpi_rs_length)(total_size +
 270                                                      acpi_rs_struct_option_length
 271                                                      (&resource->data.
 272                                                       address64.
 273                                                       resource_source));
 274                        break;
 275
 276                case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
 277                        /*
 278                         * Extended IRQ Resource:
 279                         * Add the size of each additional optional interrupt beyond the
 280                         * required 1 (4 bytes for each u32 interrupt number)
 281                         */
 282                        total_size = (acpi_rs_length)(total_size +
 283                                                      ((resource->data.
 284                                                        extended_irq.
 285                                                        interrupt_count -
 286                                                        1) * 4) +
 287                                                      /* Add the size of the optional resource_source info */
 288                                                      acpi_rs_struct_option_length
 289                                                      (&resource->data.
 290                                                       extended_irq.
 291                                                       resource_source));
 292                        break;
 293
 294                case ACPI_RESOURCE_TYPE_GPIO:
 295
 296                        total_size = (acpi_rs_length)(total_size +
 297                                                      (resource->data.gpio.
 298                                                       pin_table_length * 2) +
 299                                                      resource->data.gpio.
 300                                                      resource_source.
 301                                                      string_length +
 302                                                      resource->data.gpio.
 303                                                      vendor_length);
 304
 305                        break;
 306
 307                case ACPI_RESOURCE_TYPE_PIN_FUNCTION:
 308
 309                        total_size = (acpi_rs_length)(total_size +
 310                                                      (resource->data.
 311                                                       pin_function.
 312                                                       pin_table_length * 2) +
 313                                                      resource->data.
 314                                                      pin_function.
 315                                                      resource_source.
 316                                                      string_length +
 317                                                      resource->data.
 318                                                      pin_function.
 319                                                      vendor_length);
 320
 321                        break;
 322
 323                case ACPI_RESOURCE_TYPE_SERIAL_BUS:
 324
 325                        total_size =
 326                            acpi_gbl_aml_resource_serial_bus_sizes[resource->
 327                                                                   data.
 328                                                                   common_serial_bus.
 329                                                                   type];
 330
 331                        total_size = (acpi_rs_length)(total_size +
 332                                                      resource->data.
 333                                                      i2c_serial_bus.
 334                                                      resource_source.
 335                                                      string_length +
 336                                                      resource->data.
 337                                                      i2c_serial_bus.
 338                                                      vendor_length);
 339
 340                        break;
 341
 342                case ACPI_RESOURCE_TYPE_PIN_CONFIG:
 343
 344                        total_size = (acpi_rs_length)(total_size +
 345                                                      (resource->data.
 346                                                       pin_config.
 347                                                       pin_table_length * 2) +
 348                                                      resource->data.pin_config.
 349                                                      resource_source.
 350                                                      string_length +
 351                                                      resource->data.pin_config.
 352                                                      vendor_length);
 353
 354                        break;
 355
 356                case ACPI_RESOURCE_TYPE_PIN_GROUP:
 357
 358                        total_size = (acpi_rs_length)(total_size +
 359                                                      (resource->data.pin_group.
 360                                                       pin_table_length * 2) +
 361                                                      resource->data.pin_group.
 362                                                      resource_label.
 363                                                      string_length +
 364                                                      resource->data.pin_group.
 365                                                      vendor_length);
 366
 367                        break;
 368
 369                case ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION:
 370
 371                        total_size = (acpi_rs_length)(total_size +
 372                                                      resource->data.
 373                                                      pin_group_function.
 374                                                      resource_source.
 375                                                      string_length +
 376                                                      resource->data.
 377                                                      pin_group_function.
 378                                                      resource_source_label.
 379                                                      string_length +
 380                                                      resource->data.
 381                                                      pin_group_function.
 382                                                      vendor_length);
 383
 384                        break;
 385
 386                case ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG:
 387
 388                        total_size = (acpi_rs_length)(total_size +
 389                                                      resource->data.
 390                                                      pin_group_config.
 391                                                      resource_source.
 392                                                      string_length +
 393                                                      resource->data.
 394                                                      pin_group_config.
 395                                                      resource_source_label.
 396                                                      string_length +
 397                                                      resource->data.
 398                                                      pin_group_config.
 399                                                      vendor_length);
 400
 401                        break;
 402
 403                default:
 404
 405                        break;
 406                }
 407
 408                /* Update the total */
 409
 410                aml_size_needed += total_size;
 411
 412                /* Point to the next object */
 413
 414                resource =
 415                    ACPI_ADD_PTR(struct acpi_resource, resource,
 416                                 resource->length);
 417        }
 418
 419        /* Did not find an end_tag resource descriptor */
 420
 421        return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
 422}
 423
 424/*******************************************************************************
 425 *
 426 * FUNCTION:    acpi_rs_get_list_length
 427 *
 428 * PARAMETERS:  aml_buffer          - Pointer to the resource byte stream
 429 *              aml_buffer_length   - Size of aml_buffer
 430 *              size_needed         - Where the size needed is returned
 431 *
 432 * RETURN:      Status
 433 *
 434 * DESCRIPTION: Takes an external resource byte stream and calculates the size
 435 *              buffer needed to hold the corresponding internal resource
 436 *              descriptor linked list.
 437 *
 438 ******************************************************************************/
 439
 440acpi_status
 441acpi_rs_get_list_length(u8 *aml_buffer,
 442                        u32 aml_buffer_length, acpi_size *size_needed)
 443{
 444        acpi_status status;
 445        u8 *end_aml;
 446        u8 *buffer;
 447        u32 buffer_size;
 448        u16 temp16;
 449        u16 resource_length;
 450        u32 extra_struct_bytes;
 451        u8 resource_index;
 452        u8 minimum_aml_resource_length;
 453        union aml_resource *aml_resource;
 454
 455        ACPI_FUNCTION_TRACE(rs_get_list_length);
 456
 457        *size_needed = ACPI_RS_SIZE_MIN;        /* Minimum size is one end_tag */
 458        end_aml = aml_buffer + aml_buffer_length;
 459
 460        /* Walk the list of AML resource descriptors */
 461
 462        while (aml_buffer < end_aml) {
 463
 464                /* Validate the Resource Type and Resource Length */
 465
 466                status =
 467                    acpi_ut_validate_resource(NULL, aml_buffer,
 468                                              &resource_index);
 469                if (ACPI_FAILURE(status)) {
 470                        /*
 471                         * Exit on failure. Cannot continue because the descriptor length
 472                         * may be bogus also.
 473                         */
 474                        return_ACPI_STATUS(status);
 475                }
 476
 477                aml_resource = (void *)aml_buffer;
 478
 479                /* Get the resource length and base (minimum) AML size */
 480
 481                resource_length = acpi_ut_get_resource_length(aml_buffer);
 482                minimum_aml_resource_length =
 483                    acpi_gbl_resource_aml_sizes[resource_index];
 484
 485                /*
 486                 * Augment the size for descriptors with optional
 487                 * and/or variable length fields
 488                 */
 489                extra_struct_bytes = 0;
 490                buffer =
 491                    aml_buffer + acpi_ut_get_resource_header_length(aml_buffer);
 492
 493                switch (acpi_ut_get_resource_type(aml_buffer)) {
 494                case ACPI_RESOURCE_NAME_IRQ:
 495                        /*
 496                         * IRQ Resource:
 497                         * Get the number of bits set in the 16-bit IRQ mask
 498                         */
 499                        ACPI_MOVE_16_TO_16(&temp16, buffer);
 500                        extra_struct_bytes = acpi_rs_count_set_bits(temp16);
 501                        break;
 502
 503                case ACPI_RESOURCE_NAME_DMA:
 504                        /*
 505                         * DMA Resource:
 506                         * Get the number of bits set in the 8-bit DMA mask
 507                         */
 508                        extra_struct_bytes = acpi_rs_count_set_bits(*buffer);
 509                        break;
 510
 511                case ACPI_RESOURCE_NAME_VENDOR_SMALL:
 512                case ACPI_RESOURCE_NAME_VENDOR_LARGE:
 513                        /*
 514                         * Vendor Resource:
 515                         * Get the number of vendor data bytes
 516                         */
 517                        extra_struct_bytes = resource_length;
 518
 519                        /*
 520                         * There is already one byte included in the minimum
 521                         * descriptor size. If there are extra struct bytes,
 522                         * subtract one from the count.
 523                         */
 524                        if (extra_struct_bytes) {
 525                                extra_struct_bytes--;
 526                        }
 527                        break;
 528
 529                case ACPI_RESOURCE_NAME_END_TAG:
 530                        /*
 531                         * End Tag: This is the normal exit
 532                         */
 533                        return_ACPI_STATUS(AE_OK);
 534
 535                case ACPI_RESOURCE_NAME_ADDRESS32:
 536                case ACPI_RESOURCE_NAME_ADDRESS16:
 537                case ACPI_RESOURCE_NAME_ADDRESS64:
 538                        /*
 539                         * Address Resource:
 540                         * Add the size of the optional resource_source
 541                         */
 542                        extra_struct_bytes =
 543                            acpi_rs_stream_option_length(resource_length,
 544                                                         minimum_aml_resource_length);
 545                        break;
 546
 547                case ACPI_RESOURCE_NAME_EXTENDED_IRQ:
 548                        /*
 549                         * Extended IRQ Resource:
 550                         * Using the interrupt_table_length, add 4 bytes for each additional
 551                         * interrupt. Note: at least one interrupt is required and is
 552                         * included in the minimum descriptor size (reason for the -1)
 553                         */
 554                        extra_struct_bytes = (buffer[1] - 1) * sizeof(u32);
 555
 556                        /* Add the size of the optional resource_source */
 557
 558                        extra_struct_bytes +=
 559                            acpi_rs_stream_option_length(resource_length -
 560                                                         extra_struct_bytes,
 561                                                         minimum_aml_resource_length);
 562                        break;
 563
 564                case ACPI_RESOURCE_NAME_GPIO:
 565
 566                        /* Vendor data is optional */
 567
 568                        if (aml_resource->gpio.vendor_length) {
 569                                extra_struct_bytes +=
 570                                    aml_resource->gpio.vendor_offset -
 571                                    aml_resource->gpio.pin_table_offset +
 572                                    aml_resource->gpio.vendor_length;
 573                        } else {
 574                                extra_struct_bytes +=
 575                                    aml_resource->large_header.resource_length +
 576                                    sizeof(struct aml_resource_large_header) -
 577                                    aml_resource->gpio.pin_table_offset;
 578                        }
 579                        break;
 580
 581                case ACPI_RESOURCE_NAME_PIN_FUNCTION:
 582
 583                        /* Vendor data is optional */
 584
 585                        if (aml_resource->pin_function.vendor_length) {
 586                                extra_struct_bytes +=
 587                                    aml_resource->pin_function.vendor_offset -
 588                                    aml_resource->pin_function.
 589                                    pin_table_offset +
 590                                    aml_resource->pin_function.vendor_length;
 591                        } else {
 592                                extra_struct_bytes +=
 593                                    aml_resource->large_header.resource_length +
 594                                    sizeof(struct aml_resource_large_header) -
 595                                    aml_resource->pin_function.pin_table_offset;
 596                        }
 597                        break;
 598
 599                case ACPI_RESOURCE_NAME_SERIAL_BUS:
 600
 601                        minimum_aml_resource_length =
 602                            acpi_gbl_resource_aml_serial_bus_sizes
 603                            [aml_resource->common_serial_bus.type];
 604                        extra_struct_bytes +=
 605                            aml_resource->common_serial_bus.resource_length -
 606                            minimum_aml_resource_length;
 607                        break;
 608
 609                case ACPI_RESOURCE_NAME_PIN_CONFIG:
 610
 611                        /* Vendor data is optional */
 612
 613                        if (aml_resource->pin_config.vendor_length) {
 614                                extra_struct_bytes +=
 615                                    aml_resource->pin_config.vendor_offset -
 616                                    aml_resource->pin_config.pin_table_offset +
 617                                    aml_resource->pin_config.vendor_length;
 618                        } else {
 619                                extra_struct_bytes +=
 620                                    aml_resource->large_header.resource_length +
 621                                    sizeof(struct aml_resource_large_header) -
 622                                    aml_resource->pin_config.pin_table_offset;
 623                        }
 624                        break;
 625
 626                case ACPI_RESOURCE_NAME_PIN_GROUP:
 627
 628                        extra_struct_bytes +=
 629                            aml_resource->pin_group.vendor_offset -
 630                            aml_resource->pin_group.pin_table_offset +
 631                            aml_resource->pin_group.vendor_length;
 632
 633                        break;
 634
 635                case ACPI_RESOURCE_NAME_PIN_GROUP_FUNCTION:
 636
 637                        extra_struct_bytes +=
 638                            aml_resource->pin_group_function.vendor_offset -
 639                            aml_resource->pin_group_function.res_source_offset +
 640                            aml_resource->pin_group_function.vendor_length;
 641
 642                        break;
 643
 644                case ACPI_RESOURCE_NAME_PIN_GROUP_CONFIG:
 645
 646                        extra_struct_bytes +=
 647                            aml_resource->pin_group_config.vendor_offset -
 648                            aml_resource->pin_group_config.res_source_offset +
 649                            aml_resource->pin_group_config.vendor_length;
 650
 651                        break;
 652
 653                default:
 654
 655                        break;
 656                }
 657
 658                /*
 659                 * Update the required buffer size for the internal descriptor structs
 660                 *
 661                 * Important: Round the size up for the appropriate alignment. This
 662                 * is a requirement on IA64.
 663                 */
 664                if (acpi_ut_get_resource_type(aml_buffer) ==
 665                    ACPI_RESOURCE_NAME_SERIAL_BUS) {
 666                        buffer_size =
 667                            acpi_gbl_resource_struct_serial_bus_sizes
 668                            [aml_resource->common_serial_bus.type] +
 669                            extra_struct_bytes;
 670                } else {
 671                        buffer_size =
 672                            acpi_gbl_resource_struct_sizes[resource_index] +
 673                            extra_struct_bytes;
 674                }
 675
 676                buffer_size = (u32)ACPI_ROUND_UP_TO_NATIVE_WORD(buffer_size);
 677                *size_needed += buffer_size;
 678
 679                ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
 680                                  "Type %.2X, AmlLength %.2X InternalLength %.2X\n",
 681                                  acpi_ut_get_resource_type(aml_buffer),
 682                                  acpi_ut_get_descriptor_length(aml_buffer),
 683                                  buffer_size));
 684
 685                /*
 686                 * Point to the next resource within the AML stream using the length
 687                 * contained in the resource descriptor header
 688                 */
 689                aml_buffer += acpi_ut_get_descriptor_length(aml_buffer);
 690        }
 691
 692        /* Did not find an end_tag resource descriptor */
 693
 694        return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
 695}
 696
 697/*******************************************************************************
 698 *
 699 * FUNCTION:    acpi_rs_get_pci_routing_table_length
 700 *
 701 * PARAMETERS:  package_object          - Pointer to the package object
 702 *              buffer_size_needed      - u32 pointer of the size buffer
 703 *                                        needed to properly return the
 704 *                                        parsed data
 705 *
 706 * RETURN:      Status
 707 *
 708 * DESCRIPTION: Given a package representing a PCI routing table, this
 709 *              calculates the size of the corresponding linked list of
 710 *              descriptions.
 711 *
 712 ******************************************************************************/
 713
 714acpi_status
 715acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
 716                                     acpi_size *buffer_size_needed)
 717{
 718        u32 number_of_elements;
 719        acpi_size temp_size_needed = 0;
 720        union acpi_operand_object **top_object_list;
 721        u32 index;
 722        union acpi_operand_object *package_element;
 723        union acpi_operand_object **sub_object_list;
 724        u8 name_found;
 725        u32 table_index;
 726
 727        ACPI_FUNCTION_TRACE(rs_get_pci_routing_table_length);
 728
 729        number_of_elements = package_object->package.count;
 730
 731        /*
 732         * Calculate the size of the return buffer.
 733         * The base size is the number of elements * the sizes of the
 734         * structures. Additional space for the strings is added below.
 735         * The minus one is to subtract the size of the u8 Source[1]
 736         * member because it is added below.
 737         *
 738         * But each PRT_ENTRY structure has a pointer to a string and
 739         * the size of that string must be found.
 740         */
 741        top_object_list = package_object->package.elements;
 742
 743        for (index = 0; index < number_of_elements; index++) {
 744
 745                /* Dereference the subpackage */
 746
 747                package_element = *top_object_list;
 748
 749                /* We must have a valid Package object */
 750
 751                if (!package_element ||
 752                    (package_element->common.type != ACPI_TYPE_PACKAGE)) {
 753                        return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
 754                }
 755
 756                /*
 757                 * The sub_object_list will now point to an array of the
 758                 * four IRQ elements: Address, Pin, Source and source_index
 759                 */
 760                sub_object_list = package_element->package.elements;
 761
 762                /* Scan the irq_table_elements for the Source Name String */
 763
 764                name_found = FALSE;
 765
 766                for (table_index = 0;
 767                     table_index < package_element->package.count
 768                     && !name_found; table_index++) {
 769                        if (*sub_object_list && /* Null object allowed */
 770                            ((ACPI_TYPE_STRING ==
 771                              (*sub_object_list)->common.type) ||
 772                             ((ACPI_TYPE_LOCAL_REFERENCE ==
 773                               (*sub_object_list)->common.type) &&
 774                              ((*sub_object_list)->reference.class ==
 775                               ACPI_REFCLASS_NAME)))) {
 776                                name_found = TRUE;
 777                        } else {
 778                                /* Look at the next element */
 779
 780                                sub_object_list++;
 781                        }
 782                }
 783
 784                temp_size_needed += (sizeof(struct acpi_pci_routing_table) - 4);
 785
 786                /* Was a String type found? */
 787
 788                if (name_found) {
 789                        if ((*sub_object_list)->common.type == ACPI_TYPE_STRING) {
 790                                /*
 791                                 * The length String.Length field does not include the
 792                                 * terminating NULL, add 1
 793                                 */
 794                                temp_size_needed += ((acpi_size)
 795                                                     (*sub_object_list)->string.
 796                                                     length + 1);
 797                        } else {
 798                                temp_size_needed += acpi_ns_get_pathname_length((*sub_object_list)->reference.node);
 799                        }
 800                } else {
 801                        /*
 802                         * If no name was found, then this is a NULL, which is
 803                         * translated as a u32 zero.
 804                         */
 805                        temp_size_needed += sizeof(u32);
 806                }
 807
 808                /* Round up the size since each element must be aligned */
 809
 810                temp_size_needed = ACPI_ROUND_UP_TO_64BIT(temp_size_needed);
 811
 812                /* Point to the next union acpi_operand_object */
 813
 814                top_object_list++;
 815        }
 816
 817        /*
 818         * Add an extra element to the end of the list, essentially a
 819         * NULL terminator
 820         */
 821        *buffer_size_needed =
 822            temp_size_needed + sizeof(struct acpi_pci_routing_table);
 823        return_ACPI_STATUS(AE_OK);
 824}
 825