1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /*******************************************************************************
4 * Module Name: rsmisc - Miscellaneous resource descriptors
6 ******************************************************************************/
12 #define _COMPONENT ACPI_RESOURCES
13 ACPI_MODULE_NAME("rsmisc")
14 #define INIT_RESOURCE_TYPE(i) i->resource_offset
15 #define INIT_RESOURCE_LENGTH(i) i->aml_offset
16 #define INIT_TABLE_LENGTH(i) i->value
17 #define COMPARE_OPCODE(i) i->resource_offset
18 #define COMPARE_TARGET(i) i->aml_offset
19 #define COMPARE_VALUE(i) i->value
20 /*******************************************************************************
22 * FUNCTION: acpi_rs_convert_aml_to_resource
24 * PARAMETERS: resource - Pointer to the resource descriptor
25 * aml - Where the AML descriptor is returned
26 * info - Pointer to appropriate conversion table
30 * DESCRIPTION: Convert an external AML resource descriptor to the corresponding
31 * internal resource descriptor
33 ******************************************************************************/
35 acpi_rs_convert_aml_to_resource(struct acpi_resource
*resource
,
36 union aml_resource
*aml
,
37 struct acpi_rsconvert_info
*info
)
39 acpi_rs_length aml_resource_length
;
44 u8 flags_mode
= FALSE
;
48 ACPI_FUNCTION_TRACE(rs_convert_aml_to_resource
);
51 return_ACPI_STATUS(AE_BAD_PARAMETER
);
54 if (((acpi_size
)resource
) & 0x3) {
56 /* Each internal resource struct is expected to be 32-bit aligned */
58 ACPI_WARNING((AE_INFO
,
59 "Misaligned resource pointer (get): %p Type 0x%2.2X Length %u",
60 resource
, resource
->type
, resource
->length
));
63 /* Extract the resource Length field (does not include header length) */
65 aml_resource_length
= acpi_ut_get_resource_length(aml
);
68 * First table entry must be ACPI_RSC_INITxxx and must contain the
69 * table length (# of table entries)
71 count
= INIT_TABLE_LENGTH(info
);
76 * Source is the external AML byte stream buffer,
77 * destination is the internal resource descriptor
79 source
= ACPI_ADD_PTR(void, aml
, info
->aml_offset
);
81 ACPI_ADD_PTR(void, resource
, info
->resource_offset
);
83 switch (info
->opcode
) {
84 case ACPI_RSC_INITGET
:
86 * Get the resource type and the initial (minimum) length
88 memset(resource
, 0, INIT_RESOURCE_LENGTH(info
));
89 resource
->type
= INIT_RESOURCE_TYPE(info
);
90 resource
->length
= INIT_RESOURCE_LENGTH(info
);
93 case ACPI_RSC_INITSET
:
96 case ACPI_RSC_FLAGINIT
:
101 case ACPI_RSC_1BITFLAG
:
103 * Mask and shift the flag bit
105 ACPI_SET8(destination
,
106 ((ACPI_GET8(source
) >> info
->value
) & 0x01));
109 case ACPI_RSC_2BITFLAG
:
111 * Mask and shift the flag bits
113 ACPI_SET8(destination
,
114 ((ACPI_GET8(source
) >> info
->value
) & 0x03));
117 case ACPI_RSC_3BITFLAG
:
119 * Mask and shift the flag bits
121 ACPI_SET8(destination
,
122 ((ACPI_GET8(source
) >> info
->value
) & 0x07));
125 case ACPI_RSC_6BITFLAG
:
127 * Mask and shift the flag bits
129 ACPI_SET8(destination
,
130 ((ACPI_GET8(source
) >> info
->value
) & 0x3F));
135 item_count
= ACPI_GET8(source
);
136 ACPI_SET8(destination
, item_count
);
138 resource
->length
= resource
->length
+
139 (info
->value
* (item_count
- 1));
142 case ACPI_RSC_COUNT16
:
144 item_count
= aml_resource_length
;
145 ACPI_SET16(destination
, item_count
);
147 resource
->length
= resource
->length
+
148 (info
->value
* (item_count
- 1));
151 case ACPI_RSC_COUNT_GPIO_PIN
:
153 target
= ACPI_ADD_PTR(void, aml
, info
->value
);
154 item_count
= ACPI_GET16(target
) - ACPI_GET16(source
);
156 resource
->length
= resource
->length
+ item_count
;
157 item_count
= item_count
/ 2;
158 ACPI_SET16(destination
, item_count
);
161 case ACPI_RSC_COUNT_GPIO_VEN
:
163 item_count
= ACPI_GET8(source
);
164 ACPI_SET8(destination
, item_count
);
167 resource
->length
+ (info
->value
* item_count
);
170 case ACPI_RSC_COUNT_GPIO_RES
:
172 * Vendor data is optional (length/offset may both be zero)
173 * Examine vendor data length field first
175 target
= ACPI_ADD_PTR(void, aml
, (info
->value
+ 2));
176 if (ACPI_GET16(target
)) {
178 /* Use vendor offset to get resource source length */
180 target
= ACPI_ADD_PTR(void, aml
, info
->value
);
182 ACPI_GET16(target
) - ACPI_GET16(source
);
184 /* No vendor data to worry about */
186 item_count
= aml
->large_header
.resource_length
+
187 sizeof(struct aml_resource_large_header
) -
191 resource
->length
= resource
->length
+ item_count
;
192 ACPI_SET16(destination
, item_count
);
195 case ACPI_RSC_COUNT_SERIAL_VEN
:
197 ACPI_MOVE_16_TO_16(&temp16
, source
);
198 item_count
= temp16
- info
->value
;
200 resource
->length
= resource
->length
+ item_count
;
201 ACPI_SET16(destination
, item_count
);
204 case ACPI_RSC_COUNT_SERIAL_RES
:
206 ACPI_MOVE_16_TO_16(&temp16
, source
);
207 item_count
= (aml_resource_length
+
208 sizeof(struct aml_resource_large_header
))
209 - temp16
- info
->value
;
211 resource
->length
= resource
->length
+ item_count
;
212 ACPI_SET16(destination
, item_count
);
215 case ACPI_RSC_LENGTH
:
217 resource
->length
= resource
->length
+ info
->value
;
221 case ACPI_RSC_MOVE16
:
222 case ACPI_RSC_MOVE32
:
223 case ACPI_RSC_MOVE64
:
225 * Raw data move. Use the Info value field unless item_count has
226 * been previously initialized via a COUNT opcode
229 item_count
= info
->value
;
231 acpi_rs_move_data(destination
, source
, item_count
,
235 case ACPI_RSC_MOVE_GPIO_PIN
:
237 /* Generate and set the PIN data pointer */
239 target
= (char *)ACPI_ADD_PTR(void, resource
,
242 *(u16
**)destination
= ACPI_CAST_PTR(u16
, target
);
244 /* Copy the PIN data */
246 source
= ACPI_ADD_PTR(void, aml
, ACPI_GET16(source
));
247 acpi_rs_move_data(target
, source
, item_count
,
251 case ACPI_RSC_MOVE_GPIO_RES
:
253 /* Generate and set the resource_source string pointer */
255 target
= (char *)ACPI_ADD_PTR(void, resource
,
258 *(u8
**)destination
= ACPI_CAST_PTR(u8
, target
);
260 /* Copy the resource_source string */
262 source
= ACPI_ADD_PTR(void, aml
, ACPI_GET16(source
));
263 acpi_rs_move_data(target
, source
, item_count
,
267 case ACPI_RSC_MOVE_SERIAL_VEN
:
269 /* Generate and set the Vendor Data pointer */
271 target
= (char *)ACPI_ADD_PTR(void, resource
,
274 *(u8
**)destination
= ACPI_CAST_PTR(u8
, target
);
276 /* Copy the Vendor Data */
278 source
= ACPI_ADD_PTR(void, aml
, info
->value
);
279 acpi_rs_move_data(target
, source
, item_count
,
283 case ACPI_RSC_MOVE_SERIAL_RES
:
285 /* Generate and set the resource_source string pointer */
287 target
= (char *)ACPI_ADD_PTR(void, resource
,
290 *(u8
**)destination
= ACPI_CAST_PTR(u8
, target
);
292 /* Copy the resource_source string */
294 ACPI_MOVE_16_TO_16(&temp16
, source
);
296 ACPI_ADD_PTR(void, aml
, (temp16
+ info
->value
));
297 acpi_rs_move_data(target
, source
, item_count
,
303 memset(destination
, info
->aml_offset
, info
->value
);
308 target
= ACPI_ADD_PTR(char, resource
, info
->value
);
309 memcpy(destination
, source
, ACPI_GET16(target
));
312 case ACPI_RSC_ADDRESS
:
314 * Common handler for address descriptor flags
316 if (!acpi_rs_get_address_common(resource
, aml
)) {
318 (AE_AML_INVALID_RESOURCE_TYPE
);
322 case ACPI_RSC_SOURCE
:
324 * Optional resource_source (Index and String)
327 acpi_rs_get_resource_source(aml_resource_length
,
329 destination
, aml
, NULL
);
332 case ACPI_RSC_SOURCEX
:
334 * Optional resource_source (Index and String). This is the more
335 * complicated case used by the Interrupt() macro
337 target
= ACPI_ADD_PTR(char, resource
,
342 acpi_rs_get_resource_source(aml_resource_length
,
351 case ACPI_RSC_BITMASK
:
353 * 8-bit encoded bitmask (DMA macro)
356 acpi_rs_decode_bitmask(ACPI_GET8(source
),
359 resource
->length
+= (item_count
- 1);
362 target
= ACPI_ADD_PTR(char, resource
, info
->value
);
363 ACPI_SET8(target
, item_count
);
366 case ACPI_RSC_BITMASK16
:
368 * 16-bit encoded bitmask (IRQ macro)
370 ACPI_MOVE_16_TO_16(&temp16
, source
);
373 acpi_rs_decode_bitmask(temp16
, destination
);
375 resource
->length
+= (item_count
- 1);
378 target
= ACPI_ADD_PTR(char, resource
, info
->value
);
379 ACPI_SET8(target
, item_count
);
382 case ACPI_RSC_EXIT_NE
:
384 * control - Exit conversion if not equal
386 switch (info
->resource_offset
) {
387 case ACPI_RSC_COMPARE_AML_LENGTH
:
389 if (aml_resource_length
!= info
->value
) {
394 case ACPI_RSC_COMPARE_VALUE
:
396 if (ACPI_GET8(source
) != info
->value
) {
404 "Invalid conversion sub-opcode"));
405 return_ACPI_STATUS(AE_BAD_PARAMETER
);
411 ACPI_ERROR((AE_INFO
, "Invalid conversion opcode"));
412 return_ACPI_STATUS(AE_BAD_PARAMETER
);
422 /* Round the resource struct length up to the next boundary (32 or 64) */
424 resource
->length
= (u32
)
425 ACPI_ROUND_UP_TO_NATIVE_WORD(resource
->length
);
427 return_ACPI_STATUS(AE_OK
);
430 /*******************************************************************************
432 * FUNCTION: acpi_rs_convert_resource_to_aml
434 * PARAMETERS: resource - Pointer to the resource descriptor
435 * aml - Where the AML descriptor is returned
436 * info - Pointer to appropriate conversion table
440 * DESCRIPTION: Convert an internal resource descriptor to the corresponding
441 * external AML resource descriptor.
443 ******************************************************************************/
446 acpi_rs_convert_resource_to_aml(struct acpi_resource
*resource
,
447 union aml_resource
*aml
,
448 struct acpi_rsconvert_info
*info
)
453 acpi_rsdesc_size aml_length
= 0;
458 ACPI_FUNCTION_TRACE(rs_convert_resource_to_aml
);
461 return_ACPI_STATUS(AE_BAD_PARAMETER
);
465 * First table entry must be ACPI_RSC_INITxxx and must contain the
466 * table length (# of table entries)
468 count
= INIT_TABLE_LENGTH(info
);
472 * Source is the internal resource descriptor,
473 * destination is the external AML byte stream buffer
475 source
= ACPI_ADD_PTR(void, resource
, info
->resource_offset
);
476 destination
= ACPI_ADD_PTR(void, aml
, info
->aml_offset
);
478 switch (info
->opcode
) {
479 case ACPI_RSC_INITSET
:
481 memset(aml
, 0, INIT_RESOURCE_LENGTH(info
));
482 aml_length
= INIT_RESOURCE_LENGTH(info
);
483 acpi_rs_set_resource_header(INIT_RESOURCE_TYPE(info
),
487 case ACPI_RSC_INITGET
:
490 case ACPI_RSC_FLAGINIT
:
492 * Clear the flag byte
494 ACPI_SET8(destination
, 0);
497 case ACPI_RSC_1BITFLAG
:
499 * Mask and shift the flag bit
501 ACPI_SET_BIT(*ACPI_CAST8(destination
), (u8
)
502 ((ACPI_GET8(source
) & 0x01) << info
->
506 case ACPI_RSC_2BITFLAG
:
508 * Mask and shift the flag bits
510 ACPI_SET_BIT(*ACPI_CAST8(destination
), (u8
)
511 ((ACPI_GET8(source
) & 0x03) << info
->
515 case ACPI_RSC_3BITFLAG
:
517 * Mask and shift the flag bits
519 ACPI_SET_BIT(*ACPI_CAST8(destination
), (u8
)
520 ((ACPI_GET8(source
) & 0x07) << info
->
524 case ACPI_RSC_6BITFLAG
:
526 * Mask and shift the flag bits
528 ACPI_SET_BIT(*ACPI_CAST8(destination
), (u8
)
529 ((ACPI_GET8(source
) & 0x3F) << info
->
535 item_count
= ACPI_GET8(source
);
536 ACPI_SET8(destination
, item_count
);
539 (aml_length
+ (info
->value
* (item_count
- 1)));
542 case ACPI_RSC_COUNT16
:
544 item_count
= ACPI_GET16(source
);
545 aml_length
= (u16
) (aml_length
+ item_count
);
546 acpi_rs_set_resource_length(aml_length
, aml
);
549 case ACPI_RSC_COUNT_GPIO_PIN
:
551 item_count
= ACPI_GET16(source
);
552 ACPI_SET16(destination
, aml_length
);
554 aml_length
= (u16
)(aml_length
+ item_count
* 2);
555 target
= ACPI_ADD_PTR(void, aml
, info
->value
);
556 ACPI_SET16(target
, aml_length
);
557 acpi_rs_set_resource_length(aml_length
, aml
);
560 case ACPI_RSC_COUNT_GPIO_VEN
:
562 item_count
= ACPI_GET16(source
);
563 ACPI_SET16(destination
, item_count
);
566 (u16
)(aml_length
+ (info
->value
* item_count
));
567 acpi_rs_set_resource_length(aml_length
, aml
);
570 case ACPI_RSC_COUNT_GPIO_RES
:
572 /* Set resource source string length */
574 item_count
= ACPI_GET16(source
);
575 ACPI_SET16(destination
, aml_length
);
577 /* Compute offset for the Vendor Data */
579 aml_length
= (u16
)(aml_length
+ item_count
);
580 target
= ACPI_ADD_PTR(void, aml
, info
->value
);
582 /* Set vendor offset only if there is vendor data */
584 ACPI_SET16(target
, aml_length
);
586 acpi_rs_set_resource_length(aml_length
, aml
);
589 case ACPI_RSC_COUNT_SERIAL_VEN
:
591 item_count
= ACPI_GET16(source
);
592 ACPI_SET16(destination
, item_count
+ info
->value
);
593 aml_length
= (u16
)(aml_length
+ item_count
);
594 acpi_rs_set_resource_length(aml_length
, aml
);
597 case ACPI_RSC_COUNT_SERIAL_RES
:
599 item_count
= ACPI_GET16(source
);
600 aml_length
= (u16
)(aml_length
+ item_count
);
601 acpi_rs_set_resource_length(aml_length
, aml
);
604 case ACPI_RSC_LENGTH
:
606 acpi_rs_set_resource_length(info
->value
, aml
);
610 case ACPI_RSC_MOVE16
:
611 case ACPI_RSC_MOVE32
:
612 case ACPI_RSC_MOVE64
:
615 item_count
= info
->value
;
617 acpi_rs_move_data(destination
, source
, item_count
,
621 case ACPI_RSC_MOVE_GPIO_PIN
:
623 destination
= (char *)ACPI_ADD_PTR(void, aml
,
626 source
= *(u16
**)source
;
627 acpi_rs_move_data(destination
, source
, item_count
,
631 case ACPI_RSC_MOVE_GPIO_RES
:
633 /* Used for both resource_source string and vendor_data */
635 destination
= (char *)ACPI_ADD_PTR(void, aml
,
638 source
= *(u8
**)source
;
639 acpi_rs_move_data(destination
, source
, item_count
,
643 case ACPI_RSC_MOVE_SERIAL_VEN
:
645 destination
= (char *)ACPI_ADD_PTR(void, aml
,
648 source
= *(u8
**)source
;
649 acpi_rs_move_data(destination
, source
, item_count
,
653 case ACPI_RSC_MOVE_SERIAL_RES
:
655 destination
= (char *)ACPI_ADD_PTR(void, aml
,
658 source
= *(u8
**)source
;
659 acpi_rs_move_data(destination
, source
, item_count
,
663 case ACPI_RSC_ADDRESS
:
665 /* Set the Resource Type, General Flags, and Type-Specific Flags */
667 acpi_rs_set_address_common(aml
, resource
);
670 case ACPI_RSC_SOURCEX
:
672 * Optional resource_source (Index and String)
675 acpi_rs_set_resource_source(aml
,
678 acpi_rs_set_resource_length(aml_length
, aml
);
681 case ACPI_RSC_SOURCE
:
683 * Optional resource_source (Index and String). This is the more
684 * complicated case used by the Interrupt() macro
687 acpi_rs_set_resource_source(aml
, info
->value
,
689 acpi_rs_set_resource_length(aml_length
, aml
);
692 case ACPI_RSC_BITMASK
:
694 * 8-bit encoded bitmask (DMA macro)
696 ACPI_SET8(destination
,
697 acpi_rs_encode_bitmask(source
,
704 case ACPI_RSC_BITMASK16
:
706 * 16-bit encoded bitmask (IRQ macro)
709 acpi_rs_encode_bitmask(source
,
710 *ACPI_ADD_PTR(u8
, resource
,
712 ACPI_MOVE_16_TO_16(destination
, &temp16
);
715 case ACPI_RSC_EXIT_LE
:
717 * control - Exit conversion if less than or equal
719 if (item_count
<= info
->value
) {
724 case ACPI_RSC_EXIT_NE
:
726 * control - Exit conversion if not equal
728 switch (COMPARE_OPCODE(info
)) {
729 case ACPI_RSC_COMPARE_VALUE
:
731 if (*ACPI_ADD_PTR(u8
, resource
,
732 COMPARE_TARGET(info
)) !=
733 COMPARE_VALUE(info
)) {
741 "Invalid conversion sub-opcode"));
742 return_ACPI_STATUS(AE_BAD_PARAMETER
);
746 case ACPI_RSC_EXIT_EQ
:
748 * control - Exit conversion if equal
750 if (*ACPI_ADD_PTR(u8
, resource
,
751 COMPARE_TARGET(info
)) ==
752 COMPARE_VALUE(info
)) {
759 ACPI_ERROR((AE_INFO
, "Invalid conversion opcode"));
760 return_ACPI_STATUS(AE_BAD_PARAMETER
);
768 return_ACPI_STATUS(AE_OK
);
772 /* Previous resource validations */
774 if (aml
->ext_address64
.revision_ID
!= AML_RESOURCE_EXTENDED_ADDRESS_REVISION
) {
775 return_ACPI_STATUS(AE_SUPPORT
);
778 if (resource
->data
.start_dpf
.performance_robustness
>= 3) {
779 return_ACPI_STATUS(AE_AML_BAD_RESOURCE_VALUE
);
782 if (((aml
->irq
.flags
& 0x09) == 0x00) || ((aml
->irq
.flags
& 0x09) == 0x09)) {
784 * Only [active_high, edge_sensitive] or [active_low, level_sensitive]
785 * polarity/trigger interrupts are allowed (ACPI spec, section
786 * "IRQ Format"), so 0x00 and 0x09 are illegal.
789 "Invalid interrupt polarity/trigger in resource list, 0x%X",
791 return_ACPI_STATUS(AE_BAD_DATA
);
794 resource
->data
.extended_irq
.interrupt_count
= temp8
;
797 /* Must have at least one IRQ */
799 return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH
);
802 if (resource
->data
.dma
.transfer
== 0x03) {
803 ACPI_ERROR((AE_INFO
, "Invalid DMA.Transfer preference (3)"));
804 return_ACPI_STATUS(AE_BAD_DATA
);