1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /******************************************************************************
4 * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
6 * Copyright (C) 2000 - 2018, Intel Corp.
8 *****************************************************************************/
10 #include <acpi/acpi.h>
16 #define _COMPONENT ACPI_EXECUTER
17 ACPI_MODULE_NAME("exfield")
19 /* Local prototypes */
21 acpi_ex_get_serial_access_length(u32 accessor_type
, u32 access_length
);
23 /*******************************************************************************
25 * FUNCTION: acpi_ex_get_serial_access_length
27 * PARAMETERS: accessor_type - The type of the protocol indicated by region
28 * field access attributes
29 * access_length - The access length of the region field
31 * RETURN: Decoded access length
33 * DESCRIPTION: This routine returns the length of the generic_serial_bus
36 ******************************************************************************/
39 acpi_ex_get_serial_access_length(u32 accessor_type
, u32 access_length
)
43 switch (accessor_type
) {
44 case AML_FIELD_ATTRIB_QUICK
:
49 case AML_FIELD_ATTRIB_SEND_RCV
:
50 case AML_FIELD_ATTRIB_BYTE
:
55 case AML_FIELD_ATTRIB_WORD
:
56 case AML_FIELD_ATTRIB_WORD_CALL
:
61 case AML_FIELD_ATTRIB_MULTIBYTE
:
62 case AML_FIELD_ATTRIB_RAW_BYTES
:
63 case AML_FIELD_ATTRIB_RAW_PROCESS
:
65 length
= access_length
;
68 case AML_FIELD_ATTRIB_BLOCK
:
69 case AML_FIELD_ATTRIB_BLOCK_CALL
:
72 length
= ACPI_GSBUS_BUFFER_SIZE
- 2;
79 /*******************************************************************************
81 * FUNCTION: acpi_ex_read_data_from_field
83 * PARAMETERS: walk_state - Current execution state
84 * obj_desc - The named field
85 * ret_buffer_desc - Where the return data object is stored
89 * DESCRIPTION: Read from a named field. Returns either an Integer or a
90 * Buffer, depending on the size of the field.
92 ******************************************************************************/
95 acpi_ex_read_data_from_field(struct acpi_walk_state
*walk_state
,
96 union acpi_operand_object
*obj_desc
,
97 union acpi_operand_object
**ret_buffer_desc
)
100 union acpi_operand_object
*buffer_desc
;
106 ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field
, obj_desc
);
108 /* Parameter validation */
111 return_ACPI_STATUS(AE_AML_NO_OPERAND
);
113 if (!ret_buffer_desc
) {
114 return_ACPI_STATUS(AE_BAD_PARAMETER
);
117 if (obj_desc
->common
.type
== ACPI_TYPE_BUFFER_FIELD
) {
119 * If the buffer_field arguments have not been previously evaluated,
120 * evaluate them now and save the results.
122 if (!(obj_desc
->common
.flags
& AOPOBJ_DATA_VALID
)) {
123 status
= acpi_ds_get_buffer_field_arguments(obj_desc
);
124 if (ACPI_FAILURE(status
)) {
125 return_ACPI_STATUS(status
);
128 } else if ((obj_desc
->common
.type
== ACPI_TYPE_LOCAL_REGION_FIELD
) &&
129 (obj_desc
->field
.region_obj
->region
.space_id
==
131 || obj_desc
->field
.region_obj
->region
.space_id
==
133 || obj_desc
->field
.region_obj
->region
.space_id
==
134 ACPI_ADR_SPACE_IPMI
)) {
136 * This is an SMBus, GSBus or IPMI read. We must create a buffer to
137 * hold the data and then directly access the region handler.
139 * Note: SMBus and GSBus protocol value is passed in upper 16-bits
142 if (obj_desc
->field
.region_obj
->region
.space_id
==
143 ACPI_ADR_SPACE_SMBUS
) {
144 length
= ACPI_SMBUS_BUFFER_SIZE
;
146 ACPI_READ
| (obj_desc
->field
.attribute
<< 16);
147 } else if (obj_desc
->field
.region_obj
->region
.space_id
==
148 ACPI_ADR_SPACE_GSBUS
) {
149 accessor_type
= obj_desc
->field
.attribute
;
151 acpi_ex_get_serial_access_length(accessor_type
,
156 * Add additional 2 bytes for the generic_serial_bus data buffer:
158 * Status; (Byte 0 of the data buffer)
159 * Length; (Byte 1 of the data buffer)
160 * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
163 function
= ACPI_READ
| (accessor_type
<< 16);
166 length
= ACPI_IPMI_BUFFER_SIZE
;
167 function
= ACPI_READ
;
170 buffer_desc
= acpi_ut_create_buffer_object(length
);
172 return_ACPI_STATUS(AE_NO_MEMORY
);
175 /* Lock entire transaction if requested */
177 acpi_ex_acquire_global_lock(obj_desc
->common_field
.field_flags
);
179 /* Call the region handler for the read */
181 status
= acpi_ex_access_region(obj_desc
, 0,
187 acpi_ex_release_global_lock(obj_desc
->common_field
.field_flags
);
192 * Allocate a buffer for the contents of the field.
194 * If the field is larger than the current integer width, create
195 * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
196 * the use of arithmetic operators on the returned value if the
197 * field size is equal or smaller than an Integer.
199 * Note: Field.length is in bits.
202 (acpi_size
)ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc
->field
.bit_length
);
204 if (length
> acpi_gbl_integer_byte_width
) {
206 /* Field is too large for an Integer, create a Buffer instead */
208 buffer_desc
= acpi_ut_create_buffer_object(length
);
210 return_ACPI_STATUS(AE_NO_MEMORY
);
212 buffer
= buffer_desc
->buffer
.pointer
;
214 /* Field will fit within an Integer (normal case) */
216 buffer_desc
= acpi_ut_create_integer_object((u64
) 0);
218 return_ACPI_STATUS(AE_NO_MEMORY
);
221 length
= acpi_gbl_integer_byte_width
;
222 buffer
= &buffer_desc
->integer
.value
;
225 if ((obj_desc
->common
.type
== ACPI_TYPE_LOCAL_REGION_FIELD
) &&
226 (obj_desc
->field
.region_obj
->region
.space_id
==
227 ACPI_ADR_SPACE_GPIO
)) {
229 * For GPIO (general_purpose_io), the Address will be the bit offset
230 * from the previous Connection() operator, making it effectively a
231 * pin number index. The bit_length is the length of the field, which
232 * is thus the number of pins.
234 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD
,
235 "GPIO FieldRead [FROM]: Pin %u Bits %u\n",
236 obj_desc
->field
.pin_number_index
,
237 obj_desc
->field
.bit_length
));
239 /* Lock entire transaction if requested */
241 acpi_ex_acquire_global_lock(obj_desc
->common_field
.field_flags
);
243 /* Perform the write */
246 acpi_ex_access_region(obj_desc
, 0, (u64
*)buffer
,
249 acpi_ex_release_global_lock(obj_desc
->common_field
.field_flags
);
250 if (ACPI_FAILURE(status
)) {
251 acpi_ut_remove_reference(buffer_desc
);
253 *ret_buffer_desc
= buffer_desc
;
255 return_ACPI_STATUS(status
);
258 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD
,
259 "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n",
260 obj_desc
, obj_desc
->common
.type
, buffer
,
262 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD
,
263 "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
264 obj_desc
->common_field
.bit_length
,
265 obj_desc
->common_field
.start_field_bit_offset
,
266 obj_desc
->common_field
.base_byte_offset
));
268 /* Lock entire transaction if requested */
270 acpi_ex_acquire_global_lock(obj_desc
->common_field
.field_flags
);
272 /* Read from the field */
274 status
= acpi_ex_extract_from_field(obj_desc
, buffer
, (u32
) length
);
275 acpi_ex_release_global_lock(obj_desc
->common_field
.field_flags
);
278 if (ACPI_FAILURE(status
)) {
279 acpi_ut_remove_reference(buffer_desc
);
281 *ret_buffer_desc
= buffer_desc
;
284 return_ACPI_STATUS(status
);
287 /*******************************************************************************
289 * FUNCTION: acpi_ex_write_data_to_field
291 * PARAMETERS: source_desc - Contains data to write
292 * obj_desc - The named field
293 * result_desc - Where the return value is returned, if any
297 * DESCRIPTION: Write to a named field
299 ******************************************************************************/
302 acpi_ex_write_data_to_field(union acpi_operand_object
*source_desc
,
303 union acpi_operand_object
*obj_desc
,
304 union acpi_operand_object
**result_desc
)
309 union acpi_operand_object
*buffer_desc
;
313 ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field
, obj_desc
);
315 /* Parameter validation */
317 if (!source_desc
|| !obj_desc
) {
318 return_ACPI_STATUS(AE_AML_NO_OPERAND
);
321 if (obj_desc
->common
.type
== ACPI_TYPE_BUFFER_FIELD
) {
323 * If the buffer_field arguments have not been previously evaluated,
324 * evaluate them now and save the results.
326 if (!(obj_desc
->common
.flags
& AOPOBJ_DATA_VALID
)) {
327 status
= acpi_ds_get_buffer_field_arguments(obj_desc
);
328 if (ACPI_FAILURE(status
)) {
329 return_ACPI_STATUS(status
);
332 } else if ((obj_desc
->common
.type
== ACPI_TYPE_LOCAL_REGION_FIELD
) &&
333 (obj_desc
->field
.region_obj
->region
.space_id
==
335 || obj_desc
->field
.region_obj
->region
.space_id
==
337 || obj_desc
->field
.region_obj
->region
.space_id
==
338 ACPI_ADR_SPACE_IPMI
)) {
340 * This is an SMBus, GSBus or IPMI write. We will bypass the entire
341 * field mechanism and handoff the buffer directly to the handler.
342 * For these address spaces, the buffer is bi-directional; on a
343 * write, return data is returned in the same buffer.
345 * Source must be a buffer of sufficient size:
346 * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or
347 * ACPI_IPMI_BUFFER_SIZE.
349 * Note: SMBus and GSBus protocol type is passed in upper 16-bits
352 if (source_desc
->common
.type
!= ACPI_TYPE_BUFFER
) {
354 "SMBus/IPMI/GenericSerialBus write requires "
355 "Buffer, found type %s",
356 acpi_ut_get_object_type_name(source_desc
)));
358 return_ACPI_STATUS(AE_AML_OPERAND_TYPE
);
361 if (obj_desc
->field
.region_obj
->region
.space_id
==
362 ACPI_ADR_SPACE_SMBUS
) {
363 length
= ACPI_SMBUS_BUFFER_SIZE
;
365 ACPI_WRITE
| (obj_desc
->field
.attribute
<< 16);
366 } else if (obj_desc
->field
.region_obj
->region
.space_id
==
367 ACPI_ADR_SPACE_GSBUS
) {
368 accessor_type
= obj_desc
->field
.attribute
;
370 acpi_ex_get_serial_access_length(accessor_type
,
375 * Add additional 2 bytes for the generic_serial_bus data buffer:
377 * Status; (Byte 0 of the data buffer)
378 * Length; (Byte 1 of the data buffer)
379 * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
382 function
= ACPI_WRITE
| (accessor_type
<< 16);
385 length
= ACPI_IPMI_BUFFER_SIZE
;
386 function
= ACPI_WRITE
;
389 if (source_desc
->buffer
.length
< length
) {
391 "SMBus/IPMI/GenericSerialBus write requires "
392 "Buffer of length %u, found length %u",
393 length
, source_desc
->buffer
.length
));
395 return_ACPI_STATUS(AE_AML_BUFFER_LIMIT
);
398 /* Create the bi-directional buffer */
400 buffer_desc
= acpi_ut_create_buffer_object(length
);
402 return_ACPI_STATUS(AE_NO_MEMORY
);
405 buffer
= buffer_desc
->buffer
.pointer
;
406 memcpy(buffer
, source_desc
->buffer
.pointer
, length
);
408 /* Lock entire transaction if requested */
410 acpi_ex_acquire_global_lock(obj_desc
->common_field
.field_flags
);
413 * Perform the write (returns status and perhaps data in the
417 acpi_ex_access_region(obj_desc
, 0, (u64
*)buffer
, function
);
418 acpi_ex_release_global_lock(obj_desc
->common_field
.field_flags
);
420 *result_desc
= buffer_desc
;
421 return_ACPI_STATUS(status
);
422 } else if ((obj_desc
->common
.type
== ACPI_TYPE_LOCAL_REGION_FIELD
) &&
423 (obj_desc
->field
.region_obj
->region
.space_id
==
424 ACPI_ADR_SPACE_GPIO
)) {
426 * For GPIO (general_purpose_io), we will bypass the entire field
427 * mechanism and handoff the bit address and bit width directly to
428 * the handler. The Address will be the bit offset
429 * from the previous Connection() operator, making it effectively a
430 * pin number index. The bit_length is the length of the field, which
431 * is thus the number of pins.
433 if (source_desc
->common
.type
!= ACPI_TYPE_INTEGER
) {
434 return_ACPI_STATUS(AE_AML_OPERAND_TYPE
);
437 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD
,
438 "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n",
439 acpi_ut_get_type_name(source_desc
->common
.
441 source_desc
->common
.type
,
442 (u32
)source_desc
->integer
.value
,
443 obj_desc
->field
.pin_number_index
,
444 obj_desc
->field
.bit_length
));
446 buffer
= &source_desc
->integer
.value
;
448 /* Lock entire transaction if requested */
450 acpi_ex_acquire_global_lock(obj_desc
->common_field
.field_flags
);
452 /* Perform the write */
455 acpi_ex_access_region(obj_desc
, 0, (u64
*)buffer
,
457 acpi_ex_release_global_lock(obj_desc
->common_field
.field_flags
);
458 return_ACPI_STATUS(status
);
461 /* Get a pointer to the data to be written */
463 switch (source_desc
->common
.type
) {
464 case ACPI_TYPE_INTEGER
:
466 buffer
= &source_desc
->integer
.value
;
467 length
= sizeof(source_desc
->integer
.value
);
470 case ACPI_TYPE_BUFFER
:
472 buffer
= source_desc
->buffer
.pointer
;
473 length
= source_desc
->buffer
.length
;
476 case ACPI_TYPE_STRING
:
478 buffer
= source_desc
->string
.pointer
;
479 length
= source_desc
->string
.length
;
484 return_ACPI_STATUS(AE_AML_OPERAND_TYPE
);
487 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD
,
488 "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
490 acpi_ut_get_type_name(source_desc
->common
.type
),
491 source_desc
->common
.type
, buffer
, length
));
493 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD
,
494 "FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
496 acpi_ut_get_type_name(obj_desc
->common
.type
),
497 obj_desc
->common
.type
,
498 obj_desc
->common_field
.bit_length
,
499 obj_desc
->common_field
.start_field_bit_offset
,
500 obj_desc
->common_field
.base_byte_offset
));
502 /* Lock entire transaction if requested */
504 acpi_ex_acquire_global_lock(obj_desc
->common_field
.field_flags
);
506 /* Write to the field */
508 status
= acpi_ex_insert_into_field(obj_desc
, buffer
, length
);
509 acpi_ex_release_global_lock(obj_desc
->common_field
.field_flags
);
511 return_ACPI_STATUS(status
);