Linux 6.9-rc1
[linux-2.6-microblaze.git] / drivers / acpi / acpica / rscalc.c
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
14 ACPI_MODULE_NAME("rscalc")
15
16 /* Local prototypes */
17 static u8 acpi_rs_count_set_bits(u16 bit_field);
18
19 static acpi_rs_length
20 acpi_rs_struct_option_length(struct acpi_resource_source *resource_source);
21
22 static u32
23 acpi_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
38 static 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
68 static acpi_rs_length
69 acpi_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
101 static u32
102 acpi_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
153 acpi_status
154 acpi_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_CLOCK_INPUT:
324
325                         total_size = (acpi_rs_length)(total_size +
326                                                       resource->data.
327                                                       clock_input.
328                                                       resource_source.
329                                                       string_length);
330
331                         break;
332
333                 case ACPI_RESOURCE_TYPE_SERIAL_BUS:
334
335                         total_size =
336                             acpi_gbl_aml_resource_serial_bus_sizes[resource->
337                                                                    data.
338                                                                    common_serial_bus.
339                                                                    type];
340
341                         total_size = (acpi_rs_length)(total_size +
342                                                       resource->data.
343                                                       i2c_serial_bus.
344                                                       resource_source.
345                                                       string_length +
346                                                       resource->data.
347                                                       i2c_serial_bus.
348                                                       vendor_length);
349
350                         break;
351
352                 case ACPI_RESOURCE_TYPE_PIN_CONFIG:
353
354                         total_size = (acpi_rs_length)(total_size +
355                                                       (resource->data.
356                                                        pin_config.
357                                                        pin_table_length * 2) +
358                                                       resource->data.pin_config.
359                                                       resource_source.
360                                                       string_length +
361                                                       resource->data.pin_config.
362                                                       vendor_length);
363
364                         break;
365
366                 case ACPI_RESOURCE_TYPE_PIN_GROUP:
367
368                         total_size = (acpi_rs_length)(total_size +
369                                                       (resource->data.pin_group.
370                                                        pin_table_length * 2) +
371                                                       resource->data.pin_group.
372                                                       resource_label.
373                                                       string_length +
374                                                       resource->data.pin_group.
375                                                       vendor_length);
376
377                         break;
378
379                 case ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION:
380
381                         total_size = (acpi_rs_length)(total_size +
382                                                       resource->data.
383                                                       pin_group_function.
384                                                       resource_source.
385                                                       string_length +
386                                                       resource->data.
387                                                       pin_group_function.
388                                                       resource_source_label.
389                                                       string_length +
390                                                       resource->data.
391                                                       pin_group_function.
392                                                       vendor_length);
393
394                         break;
395
396                 case ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG:
397
398                         total_size = (acpi_rs_length)(total_size +
399                                                       resource->data.
400                                                       pin_group_config.
401                                                       resource_source.
402                                                       string_length +
403                                                       resource->data.
404                                                       pin_group_config.
405                                                       resource_source_label.
406                                                       string_length +
407                                                       resource->data.
408                                                       pin_group_config.
409                                                       vendor_length);
410
411                         break;
412
413                 default:
414
415                         break;
416                 }
417
418                 /* Update the total */
419
420                 aml_size_needed += total_size;
421
422                 /* Point to the next object */
423
424                 resource =
425                     ACPI_ADD_PTR(struct acpi_resource, resource,
426                                  resource->length);
427         }
428
429         /* Did not find an end_tag resource descriptor */
430
431         return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
432 }
433
434 /*******************************************************************************
435  *
436  * FUNCTION:    acpi_rs_get_list_length
437  *
438  * PARAMETERS:  aml_buffer          - Pointer to the resource byte stream
439  *              aml_buffer_length   - Size of aml_buffer
440  *              size_needed         - Where the size needed is returned
441  *
442  * RETURN:      Status
443  *
444  * DESCRIPTION: Takes an external resource byte stream and calculates the size
445  *              buffer needed to hold the corresponding internal resource
446  *              descriptor linked list.
447  *
448  ******************************************************************************/
449
450 acpi_status
451 acpi_rs_get_list_length(u8 *aml_buffer,
452                         u32 aml_buffer_length, acpi_size *size_needed)
453 {
454         acpi_status status;
455         u8 *end_aml;
456         u8 *buffer;
457         u32 buffer_size;
458         u16 temp16;
459         u16 resource_length;
460         u32 extra_struct_bytes;
461         u8 resource_index;
462         u8 minimum_aml_resource_length;
463         union aml_resource *aml_resource;
464
465         ACPI_FUNCTION_TRACE(rs_get_list_length);
466
467         *size_needed = ACPI_RS_SIZE_MIN;        /* Minimum size is one end_tag */
468         end_aml = aml_buffer + aml_buffer_length;
469
470         /* Walk the list of AML resource descriptors */
471
472         while (aml_buffer < end_aml) {
473
474                 /* Validate the Resource Type and Resource Length */
475
476                 status =
477                     acpi_ut_validate_resource(NULL, aml_buffer,
478                                               &resource_index);
479                 if (ACPI_FAILURE(status)) {
480                         /*
481                          * Exit on failure. Cannot continue because the descriptor length
482                          * may be bogus also.
483                          */
484                         return_ACPI_STATUS(status);
485                 }
486
487                 aml_resource = (void *)aml_buffer;
488
489                 /* Get the resource length and base (minimum) AML size */
490
491                 resource_length = acpi_ut_get_resource_length(aml_buffer);
492                 minimum_aml_resource_length =
493                     acpi_gbl_resource_aml_sizes[resource_index];
494
495                 /*
496                  * Augment the size for descriptors with optional
497                  * and/or variable length fields
498                  */
499                 extra_struct_bytes = 0;
500                 buffer =
501                     aml_buffer + acpi_ut_get_resource_header_length(aml_buffer);
502
503                 switch (acpi_ut_get_resource_type(aml_buffer)) {
504                 case ACPI_RESOURCE_NAME_IRQ:
505                         /*
506                          * IRQ Resource:
507                          * Get the number of bits set in the 16-bit IRQ mask
508                          */
509                         ACPI_MOVE_16_TO_16(&temp16, buffer);
510                         extra_struct_bytes = acpi_rs_count_set_bits(temp16);
511                         break;
512
513                 case ACPI_RESOURCE_NAME_DMA:
514                         /*
515                          * DMA Resource:
516                          * Get the number of bits set in the 8-bit DMA mask
517                          */
518                         extra_struct_bytes = acpi_rs_count_set_bits(*buffer);
519                         break;
520
521                 case ACPI_RESOURCE_NAME_VENDOR_SMALL:
522                 case ACPI_RESOURCE_NAME_VENDOR_LARGE:
523                         /*
524                          * Vendor Resource:
525                          * Get the number of vendor data bytes
526                          */
527                         extra_struct_bytes = resource_length;
528
529                         /*
530                          * There is already one byte included in the minimum
531                          * descriptor size. If there are extra struct bytes,
532                          * subtract one from the count.
533                          */
534                         if (extra_struct_bytes) {
535                                 extra_struct_bytes--;
536                         }
537                         break;
538
539                 case ACPI_RESOURCE_NAME_END_TAG:
540                         /*
541                          * End Tag: This is the normal exit
542                          */
543                         return_ACPI_STATUS(AE_OK);
544
545                 case ACPI_RESOURCE_NAME_ADDRESS32:
546                 case ACPI_RESOURCE_NAME_ADDRESS16:
547                 case ACPI_RESOURCE_NAME_ADDRESS64:
548                         /*
549                          * Address Resource:
550                          * Add the size of the optional resource_source
551                          */
552                         extra_struct_bytes =
553                             acpi_rs_stream_option_length(resource_length,
554                                                          minimum_aml_resource_length);
555                         break;
556
557                 case ACPI_RESOURCE_NAME_EXTENDED_IRQ:
558                         /*
559                          * Extended IRQ Resource:
560                          * Using the interrupt_table_length, add 4 bytes for each additional
561                          * interrupt. Note: at least one interrupt is required and is
562                          * included in the minimum descriptor size (reason for the -1)
563                          */
564                         extra_struct_bytes = (buffer[1] - 1) * sizeof(u32);
565
566                         /* Add the size of the optional resource_source */
567
568                         extra_struct_bytes +=
569                             acpi_rs_stream_option_length(resource_length -
570                                                          extra_struct_bytes,
571                                                          minimum_aml_resource_length);
572                         break;
573
574                 case ACPI_RESOURCE_NAME_GPIO:
575
576                         /* Vendor data is optional */
577
578                         if (aml_resource->gpio.vendor_length) {
579                                 extra_struct_bytes +=
580                                     aml_resource->gpio.vendor_offset -
581                                     aml_resource->gpio.pin_table_offset +
582                                     aml_resource->gpio.vendor_length;
583                         } else {
584                                 extra_struct_bytes +=
585                                     aml_resource->large_header.resource_length +
586                                     sizeof(struct aml_resource_large_header) -
587                                     aml_resource->gpio.pin_table_offset;
588                         }
589                         break;
590
591                 case ACPI_RESOURCE_NAME_PIN_FUNCTION:
592
593                         /* Vendor data is optional */
594
595                         if (aml_resource->pin_function.vendor_length) {
596                                 extra_struct_bytes +=
597                                     aml_resource->pin_function.vendor_offset -
598                                     aml_resource->pin_function.
599                                     pin_table_offset +
600                                     aml_resource->pin_function.vendor_length;
601                         } else {
602                                 extra_struct_bytes +=
603                                     aml_resource->large_header.resource_length +
604                                     sizeof(struct aml_resource_large_header) -
605                                     aml_resource->pin_function.pin_table_offset;
606                         }
607                         break;
608
609                 case ACPI_RESOURCE_NAME_SERIAL_BUS:{
610
611                                 /* Avoid undefined behavior: member access within misaligned address */
612
613                                 struct aml_resource_common_serialbus
614                                     common_serial_bus;
615                                 memcpy(&common_serial_bus, aml_resource,
616                                        sizeof(common_serial_bus));
617
618                                 minimum_aml_resource_length =
619                                     acpi_gbl_resource_aml_serial_bus_sizes
620                                     [common_serial_bus.type];
621                                 extra_struct_bytes +=
622                                     common_serial_bus.resource_length -
623                                     minimum_aml_resource_length;
624                                 break;
625                         }
626
627                 case ACPI_RESOURCE_NAME_PIN_CONFIG:
628
629                         /* Vendor data is optional */
630
631                         if (aml_resource->pin_config.vendor_length) {
632                                 extra_struct_bytes +=
633                                     aml_resource->pin_config.vendor_offset -
634                                     aml_resource->pin_config.pin_table_offset +
635                                     aml_resource->pin_config.vendor_length;
636                         } else {
637                                 extra_struct_bytes +=
638                                     aml_resource->large_header.resource_length +
639                                     sizeof(struct aml_resource_large_header) -
640                                     aml_resource->pin_config.pin_table_offset;
641                         }
642                         break;
643
644                 case ACPI_RESOURCE_NAME_PIN_GROUP:
645
646                         extra_struct_bytes +=
647                             aml_resource->pin_group.vendor_offset -
648                             aml_resource->pin_group.pin_table_offset +
649                             aml_resource->pin_group.vendor_length;
650
651                         break;
652
653                 case ACPI_RESOURCE_NAME_PIN_GROUP_FUNCTION:
654
655                         extra_struct_bytes +=
656                             aml_resource->pin_group_function.vendor_offset -
657                             aml_resource->pin_group_function.res_source_offset +
658                             aml_resource->pin_group_function.vendor_length;
659
660                         break;
661
662                 case ACPI_RESOURCE_NAME_PIN_GROUP_CONFIG:
663
664                         extra_struct_bytes +=
665                             aml_resource->pin_group_config.vendor_offset -
666                             aml_resource->pin_group_config.res_source_offset +
667                             aml_resource->pin_group_config.vendor_length;
668
669                         break;
670
671                 case ACPI_RESOURCE_NAME_CLOCK_INPUT:
672                         extra_struct_bytes =
673                             acpi_rs_stream_option_length(resource_length,
674                                                          minimum_aml_resource_length);
675
676                         break;
677
678                 default:
679
680                         break;
681                 }
682
683                 /*
684                  * Update the required buffer size for the internal descriptor structs
685                  *
686                  * Important: Round the size up for the appropriate alignment. This
687                  * is a requirement on IA64.
688                  */
689                 if (acpi_ut_get_resource_type(aml_buffer) ==
690                     ACPI_RESOURCE_NAME_SERIAL_BUS) {
691
692                         /* Avoid undefined behavior: member access within misaligned address */
693
694                         struct aml_resource_common_serialbus common_serial_bus;
695                         memcpy(&common_serial_bus, aml_resource,
696                                sizeof(common_serial_bus));
697
698                         buffer_size =
699                             acpi_gbl_resource_struct_serial_bus_sizes
700                             [common_serial_bus.type] + extra_struct_bytes;
701                 } else {
702                         buffer_size =
703                             acpi_gbl_resource_struct_sizes[resource_index] +
704                             extra_struct_bytes;
705                 }
706
707                 buffer_size = (u32)ACPI_ROUND_UP_TO_NATIVE_WORD(buffer_size);
708                 *size_needed += buffer_size;
709
710                 ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES,
711                                   "Type %.2X, AmlLength %.2X InternalLength %.2X%8X\n",
712                                   acpi_ut_get_resource_type(aml_buffer),
713                                   acpi_ut_get_descriptor_length(aml_buffer),
714                                   ACPI_FORMAT_UINT64(*size_needed)));
715
716                 /*
717                  * Point to the next resource within the AML stream using the length
718                  * contained in the resource descriptor header
719                  */
720                 aml_buffer += acpi_ut_get_descriptor_length(aml_buffer);
721         }
722
723         /* Did not find an end_tag resource descriptor */
724
725         return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
726 }
727
728 /*******************************************************************************
729  *
730  * FUNCTION:    acpi_rs_get_pci_routing_table_length
731  *
732  * PARAMETERS:  package_object          - Pointer to the package object
733  *              buffer_size_needed      - u32 pointer of the size buffer
734  *                                        needed to properly return the
735  *                                        parsed data
736  *
737  * RETURN:      Status
738  *
739  * DESCRIPTION: Given a package representing a PCI routing table, this
740  *              calculates the size of the corresponding linked list of
741  *              descriptions.
742  *
743  ******************************************************************************/
744
745 acpi_status
746 acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
747                                      acpi_size *buffer_size_needed)
748 {
749         u32 number_of_elements;
750         acpi_size temp_size_needed = 0;
751         union acpi_operand_object **top_object_list;
752         u32 index;
753         union acpi_operand_object *package_element;
754         union acpi_operand_object **sub_object_list;
755         u8 name_found;
756         u32 table_index;
757
758         ACPI_FUNCTION_TRACE(rs_get_pci_routing_table_length);
759
760         number_of_elements = package_object->package.count;
761
762         /*
763          * Calculate the size of the return buffer.
764          * The base size is the number of elements * the sizes of the
765          * structures. Additional space for the strings is added below.
766          * The minus one is to subtract the size of the u8 Source[1]
767          * member because it is added below.
768          *
769          * But each PRT_ENTRY structure has a pointer to a string and
770          * the size of that string must be found.
771          */
772         top_object_list = package_object->package.elements;
773
774         for (index = 0; index < number_of_elements; index++) {
775
776                 /* Dereference the subpackage */
777
778                 package_element = *top_object_list;
779
780                 /* We must have a valid Package object */
781
782                 if (!package_element ||
783                     (package_element->common.type != ACPI_TYPE_PACKAGE)) {
784                         return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
785                 }
786
787                 /*
788                  * The sub_object_list will now point to an array of the
789                  * four IRQ elements: Address, Pin, Source and source_index
790                  */
791                 sub_object_list = package_element->package.elements;
792
793                 /* Scan the irq_table_elements for the Source Name String */
794
795                 name_found = FALSE;
796
797                 for (table_index = 0;
798                      table_index < package_element->package.count
799                      && !name_found; table_index++) {
800                         if (*sub_object_list && /* Null object allowed */
801                             ((ACPI_TYPE_STRING ==
802                               (*sub_object_list)->common.type) ||
803                              ((ACPI_TYPE_LOCAL_REFERENCE ==
804                                (*sub_object_list)->common.type) &&
805                               ((*sub_object_list)->reference.class ==
806                                ACPI_REFCLASS_NAME)))) {
807                                 name_found = TRUE;
808                         } else {
809                                 /* Look at the next element */
810
811                                 sub_object_list++;
812                         }
813                 }
814
815                 temp_size_needed += (sizeof(struct acpi_pci_routing_table) - 4);
816
817                 /* Was a String type found? */
818
819                 if (name_found) {
820                         if ((*sub_object_list)->common.type == ACPI_TYPE_STRING) {
821                                 /*
822                                  * The length String.Length field does not include the
823                                  * terminating NULL, add 1
824                                  */
825                                 temp_size_needed += ((acpi_size)
826                                                      (*sub_object_list)->string.
827                                                      length + 1);
828                         } else {
829                                 temp_size_needed += acpi_ns_get_pathname_length((*sub_object_list)->reference.node);
830                         }
831                 } else {
832                         /*
833                          * If no name was found, then this is a NULL, which is
834                          * translated as a u32 zero.
835                          */
836                         temp_size_needed += sizeof(u32);
837                 }
838
839                 /* Round up the size since each element must be aligned */
840
841                 temp_size_needed = ACPI_ROUND_UP_TO_64BIT(temp_size_needed);
842
843                 /* Point to the next union acpi_operand_object */
844
845                 top_object_list++;
846         }
847
848         /*
849          * Add an extra element to the end of the list, essentially a
850          * NULL terminator
851          */
852         *buffer_size_needed =
853             temp_size_needed + sizeof(struct acpi_pci_routing_table);
854         return_ACPI_STATUS(AE_OK);
855 }