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_source: &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_source: &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_source: &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_source: &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 ; |
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: aml_buffer, |
478 | return_index: &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: 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: aml_buffer); |
502 | |
503 | switch (acpi_ut_get_resource_type(aml: 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(bit_field: 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(bit_field: *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: 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: 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: 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(node: (*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 | } |
856 | |