1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: exprep - ACPI AML field prep utilities |
5 | * |
6 | * Copyright (C) 2000 - 2023, Intel Corp. |
7 | * |
8 | *****************************************************************************/ |
9 | |
10 | #include <acpi/acpi.h> |
11 | #include "accommon.h" |
12 | #include "acinterp.h" |
13 | #include "amlcode.h" |
14 | #include "acnamesp.h" |
15 | #include "acdispat.h" |
16 | |
17 | #define _COMPONENT ACPI_EXECUTER |
18 | ACPI_MODULE_NAME("exprep" ) |
19 | |
20 | /* Local prototypes */ |
21 | static u32 |
22 | acpi_ex_decode_field_access(union acpi_operand_object *obj_desc, |
23 | u8 field_flags, u32 * return_byte_alignment); |
24 | |
25 | #ifdef ACPI_UNDER_DEVELOPMENT |
26 | |
27 | static u32 |
28 | acpi_ex_generate_access(u32 field_bit_offset, |
29 | u32 field_bit_length, u32 region_length); |
30 | |
31 | /******************************************************************************* |
32 | * |
33 | * FUNCTION: acpi_ex_generate_access |
34 | * |
35 | * PARAMETERS: field_bit_offset - Start of field within parent region/buffer |
36 | * field_bit_length - Length of field in bits |
37 | * region_length - Length of parent in bytes |
38 | * |
39 | * RETURN: Field granularity (8, 16, 32 or 64) and |
40 | * byte_alignment (1, 2, 3, or 4) |
41 | * |
42 | * DESCRIPTION: Generate an optimal access width for fields defined with the |
43 | * any_acc keyword. |
44 | * |
45 | * NOTE: Need to have the region_length in order to check for boundary |
46 | * conditions (end-of-region). However, the region_length is a deferred |
47 | * operation. Therefore, to complete this implementation, the generation |
48 | * of this access width must be deferred until the region length has |
49 | * been evaluated. |
50 | * |
51 | ******************************************************************************/ |
52 | |
53 | static u32 |
54 | acpi_ex_generate_access(u32 field_bit_offset, |
55 | u32 field_bit_length, u32 region_length) |
56 | { |
57 | u32 field_byte_length; |
58 | u32 field_byte_offset; |
59 | u32 field_byte_end_offset; |
60 | u32 access_byte_width; |
61 | u32 field_start_offset; |
62 | u32 field_end_offset; |
63 | u32 minimum_access_width = 0xFFFFFFFF; |
64 | u32 minimum_accesses = 0xFFFFFFFF; |
65 | u32 accesses; |
66 | |
67 | ACPI_FUNCTION_TRACE(ex_generate_access); |
68 | |
69 | /* Round Field start offset and length to "minimal" byte boundaries */ |
70 | |
71 | field_byte_offset = ACPI_DIV_8(ACPI_ROUND_DOWN(field_bit_offset, 8)); |
72 | |
73 | field_byte_end_offset = |
74 | ACPI_DIV_8(ACPI_ROUND_UP(field_bit_length + field_bit_offset, 8)); |
75 | |
76 | field_byte_length = field_byte_end_offset - field_byte_offset; |
77 | |
78 | ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
79 | "Bit length %u, Bit offset %u\n" , |
80 | field_bit_length, field_bit_offset)); |
81 | |
82 | ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
83 | "Byte Length %u, Byte Offset %u, End Offset %u\n" , |
84 | field_byte_length, field_byte_offset, |
85 | field_byte_end_offset)); |
86 | |
87 | /* |
88 | * Iterative search for the maximum access width that is both aligned |
89 | * and does not go beyond the end of the region |
90 | * |
91 | * Start at byte_acc and work upwards to qword_acc max. (1,2,4,8 bytes) |
92 | */ |
93 | for (access_byte_width = 1; access_byte_width <= 8; |
94 | access_byte_width <<= 1) { |
95 | /* |
96 | * 1) Round end offset up to next access boundary and make sure that |
97 | * this does not go beyond the end of the parent region. |
98 | * 2) When the Access width is greater than the field_byte_length, we |
99 | * are done. (This does not optimize for the perfectly aligned |
100 | * case yet). |
101 | */ |
102 | if (ACPI_ROUND_UP(field_byte_end_offset, access_byte_width) <= |
103 | region_length) { |
104 | field_start_offset = |
105 | ACPI_ROUND_DOWN(field_byte_offset, |
106 | access_byte_width) / |
107 | access_byte_width; |
108 | |
109 | field_end_offset = |
110 | ACPI_ROUND_UP((field_byte_length + |
111 | field_byte_offset), |
112 | access_byte_width) / |
113 | access_byte_width; |
114 | |
115 | accesses = field_end_offset - field_start_offset; |
116 | |
117 | ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
118 | "AccessWidth %u end is within region\n" , |
119 | access_byte_width)); |
120 | |
121 | ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
122 | "Field Start %u, Field End %u -- requires %u accesses\n" , |
123 | field_start_offset, field_end_offset, |
124 | accesses)); |
125 | |
126 | /* Single access is optimal */ |
127 | |
128 | if (accesses <= 1) { |
129 | ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
130 | "Entire field can be accessed " |
131 | "with one operation of size %u\n" , |
132 | access_byte_width)); |
133 | return_VALUE(access_byte_width); |
134 | } |
135 | |
136 | /* |
137 | * Fits in the region, but requires more than one read/write. |
138 | * try the next wider access on next iteration |
139 | */ |
140 | if (accesses < minimum_accesses) { |
141 | minimum_accesses = accesses; |
142 | minimum_access_width = access_byte_width; |
143 | } |
144 | } else { |
145 | ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
146 | "AccessWidth %u end is NOT within region\n" , |
147 | access_byte_width)); |
148 | if (access_byte_width == 1) { |
149 | ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
150 | "Field goes beyond end-of-region!\n" )); |
151 | |
152 | /* Field does not fit in the region at all */ |
153 | |
154 | return_VALUE(0); |
155 | } |
156 | |
157 | /* |
158 | * This width goes beyond the end-of-region, back off to |
159 | * previous access |
160 | */ |
161 | ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
162 | "Backing off to previous optimal access width of %u\n" , |
163 | minimum_access_width)); |
164 | return_VALUE(minimum_access_width); |
165 | } |
166 | } |
167 | |
168 | /* |
169 | * Could not read/write field with one operation, |
170 | * just use max access width |
171 | */ |
172 | ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
173 | "Cannot access field in one operation, using width 8\n" )); |
174 | |
175 | return_VALUE(8); |
176 | } |
177 | #endif /* ACPI_UNDER_DEVELOPMENT */ |
178 | |
179 | /******************************************************************************* |
180 | * |
181 | * FUNCTION: acpi_ex_decode_field_access |
182 | * |
183 | * PARAMETERS: obj_desc - Field object |
184 | * field_flags - Encoded fieldflags (contains access bits) |
185 | * return_byte_alignment - Where the byte alignment is returned |
186 | * |
187 | * RETURN: Field granularity (8, 16, 32 or 64) and |
188 | * byte_alignment (1, 2, 3, or 4) |
189 | * |
190 | * DESCRIPTION: Decode the access_type bits of a field definition. |
191 | * |
192 | ******************************************************************************/ |
193 | |
194 | static u32 |
195 | acpi_ex_decode_field_access(union acpi_operand_object *obj_desc, |
196 | u8 field_flags, u32 * return_byte_alignment) |
197 | { |
198 | u32 access; |
199 | u32 byte_alignment; |
200 | u32 bit_length; |
201 | |
202 | ACPI_FUNCTION_TRACE(ex_decode_field_access); |
203 | |
204 | access = (field_flags & AML_FIELD_ACCESS_TYPE_MASK); |
205 | |
206 | switch (access) { |
207 | case AML_FIELD_ACCESS_ANY: |
208 | |
209 | #ifdef ACPI_UNDER_DEVELOPMENT |
210 | byte_alignment = |
211 | acpi_ex_generate_access(obj_desc->common_field. |
212 | start_field_bit_offset, |
213 | obj_desc->common_field.bit_length, |
214 | 0xFFFFFFFF |
215 | /* Temp until we pass region_length as parameter */ |
216 | ); |
217 | bit_length = byte_alignment * 8; |
218 | #endif |
219 | |
220 | byte_alignment = 1; |
221 | bit_length = 8; |
222 | break; |
223 | |
224 | case AML_FIELD_ACCESS_BYTE: |
225 | case AML_FIELD_ACCESS_BUFFER: /* ACPI 2.0 (SMBus Buffer) */ |
226 | |
227 | byte_alignment = 1; |
228 | bit_length = 8; |
229 | break; |
230 | |
231 | case AML_FIELD_ACCESS_WORD: |
232 | |
233 | byte_alignment = 2; |
234 | bit_length = 16; |
235 | break; |
236 | |
237 | case AML_FIELD_ACCESS_DWORD: |
238 | |
239 | byte_alignment = 4; |
240 | bit_length = 32; |
241 | break; |
242 | |
243 | case AML_FIELD_ACCESS_QWORD: /* ACPI 2.0 */ |
244 | |
245 | byte_alignment = 8; |
246 | bit_length = 64; |
247 | break; |
248 | |
249 | default: |
250 | |
251 | /* Invalid field access type */ |
252 | |
253 | ACPI_ERROR((AE_INFO, "Unknown field access type 0x%X" , access)); |
254 | |
255 | return_UINT32(0); |
256 | } |
257 | |
258 | if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) { |
259 | /* |
260 | * buffer_field access can be on any byte boundary, so the |
261 | * byte_alignment is always 1 byte -- regardless of any byte_alignment |
262 | * implied by the field access type. |
263 | */ |
264 | byte_alignment = 1; |
265 | } |
266 | |
267 | *return_byte_alignment = byte_alignment; |
268 | return_UINT32(bit_length); |
269 | } |
270 | |
271 | /******************************************************************************* |
272 | * |
273 | * FUNCTION: acpi_ex_prep_common_field_object |
274 | * |
275 | * PARAMETERS: obj_desc - The field object |
276 | * field_flags - Access, lock_rule, and update_rule. |
277 | * The format of a field_flag is described |
278 | * in the ACPI specification |
279 | * field_attribute - Special attributes (not used) |
280 | * field_bit_position - Field start position |
281 | * field_bit_length - Field length in number of bits |
282 | * |
283 | * RETURN: Status |
284 | * |
285 | * DESCRIPTION: Initialize the areas of the field object that are common |
286 | * to the various types of fields. Note: This is very "sensitive" |
287 | * code because we are solving the general case for field |
288 | * alignment. |
289 | * |
290 | ******************************************************************************/ |
291 | |
292 | acpi_status |
293 | acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc, |
294 | u8 field_flags, |
295 | u8 field_attribute, |
296 | u32 field_bit_position, u32 field_bit_length) |
297 | { |
298 | u32 access_bit_width; |
299 | u32 byte_alignment; |
300 | u32 nearest_byte_address; |
301 | |
302 | ACPI_FUNCTION_TRACE(ex_prep_common_field_object); |
303 | |
304 | /* |
305 | * Note: the structure being initialized is the |
306 | * ACPI_COMMON_FIELD_INFO; No structure fields outside of the common |
307 | * area are initialized by this procedure. |
308 | */ |
309 | obj_desc->common_field.field_flags = field_flags; |
310 | obj_desc->common_field.attribute = field_attribute; |
311 | obj_desc->common_field.bit_length = field_bit_length; |
312 | |
313 | /* |
314 | * Decode the access type so we can compute offsets. The access type gives |
315 | * two pieces of information - the width of each field access and the |
316 | * necessary byte_alignment (address granularity) of the access. |
317 | * |
318 | * For any_acc, the access_bit_width is the largest width that is both |
319 | * necessary and possible in an attempt to access the whole field in one |
320 | * I/O operation. However, for any_acc, the byte_alignment is always one |
321 | * byte. |
322 | * |
323 | * For all Buffer Fields, the byte_alignment is always one byte. |
324 | * |
325 | * For all other access types (Byte, Word, Dword, Qword), the Bitwidth is |
326 | * the same (equivalent) as the byte_alignment. |
327 | */ |
328 | access_bit_width = |
329 | acpi_ex_decode_field_access(obj_desc, field_flags, return_byte_alignment: &byte_alignment); |
330 | if (!access_bit_width) { |
331 | return_ACPI_STATUS(AE_AML_OPERAND_VALUE); |
332 | } |
333 | |
334 | /* Setup width (access granularity) fields (values are: 1, 2, 4, 8) */ |
335 | |
336 | obj_desc->common_field.access_byte_width = (u8) |
337 | ACPI_DIV_8(access_bit_width); |
338 | |
339 | /* |
340 | * base_byte_offset is the address of the start of the field within the |
341 | * region. It is the byte address of the first *datum* (field-width data |
342 | * unit) of the field. (i.e., the first datum that contains at least the |
343 | * first *bit* of the field.) |
344 | * |
345 | * Note: byte_alignment is always either equal to the access_bit_width or 8 |
346 | * (Byte access), and it defines the addressing granularity of the parent |
347 | * region or buffer. |
348 | */ |
349 | nearest_byte_address = |
350 | ACPI_ROUND_BITS_DOWN_TO_BYTES(field_bit_position); |
351 | obj_desc->common_field.base_byte_offset = (u32) |
352 | ACPI_ROUND_DOWN(nearest_byte_address, byte_alignment); |
353 | |
354 | /* |
355 | * start_field_bit_offset is the offset of the first bit of the field within |
356 | * a field datum. |
357 | */ |
358 | obj_desc->common_field.start_field_bit_offset = (u8) |
359 | (field_bit_position - |
360 | ACPI_MUL_8(obj_desc->common_field.base_byte_offset)); |
361 | |
362 | return_ACPI_STATUS(AE_OK); |
363 | } |
364 | |
365 | /******************************************************************************* |
366 | * |
367 | * FUNCTION: acpi_ex_prep_field_value |
368 | * |
369 | * PARAMETERS: info - Contains all field creation info |
370 | * |
371 | * RETURN: Status |
372 | * |
373 | * DESCRIPTION: Construct an object of type union acpi_operand_object with a |
374 | * subtype of def_field and connect it to the parent Node. |
375 | * |
376 | ******************************************************************************/ |
377 | |
378 | acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) |
379 | { |
380 | union acpi_operand_object *obj_desc; |
381 | union acpi_operand_object *second_desc = NULL; |
382 | acpi_status status; |
383 | u32 access_byte_width; |
384 | u32 type; |
385 | |
386 | ACPI_FUNCTION_TRACE(ex_prep_field_value); |
387 | |
388 | /* Parameter validation */ |
389 | |
390 | if (info->field_type != ACPI_TYPE_LOCAL_INDEX_FIELD) { |
391 | if (!info->region_node) { |
392 | ACPI_ERROR((AE_INFO, "Null RegionNode" )); |
393 | return_ACPI_STATUS(AE_AML_NO_OPERAND); |
394 | } |
395 | |
396 | type = acpi_ns_get_type(node: info->region_node); |
397 | if (type != ACPI_TYPE_REGION) { |
398 | ACPI_ERROR((AE_INFO, |
399 | "Needed Region, found type 0x%X (%s)" , type, |
400 | acpi_ut_get_type_name(type))); |
401 | |
402 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
403 | } |
404 | } |
405 | |
406 | /* Allocate a new field object */ |
407 | |
408 | obj_desc = acpi_ut_create_internal_object(info->field_type); |
409 | if (!obj_desc) { |
410 | return_ACPI_STATUS(AE_NO_MEMORY); |
411 | } |
412 | |
413 | /* Initialize areas of the object that are common to all fields */ |
414 | |
415 | obj_desc->common_field.node = info->field_node; |
416 | status = acpi_ex_prep_common_field_object(obj_desc, |
417 | field_flags: info->field_flags, |
418 | field_attribute: info->attribute, |
419 | field_bit_position: info->field_bit_position, |
420 | field_bit_length: info->field_bit_length); |
421 | if (ACPI_FAILURE(status)) { |
422 | acpi_ut_delete_object_desc(object: obj_desc); |
423 | return_ACPI_STATUS(status); |
424 | } |
425 | |
426 | /* Initialize areas of the object that are specific to the field type */ |
427 | |
428 | switch (info->field_type) { |
429 | case ACPI_TYPE_LOCAL_REGION_FIELD: |
430 | |
431 | obj_desc->field.region_obj = |
432 | acpi_ns_get_attached_object(node: info->region_node); |
433 | |
434 | /* Fields specific to generic_serial_bus fields */ |
435 | |
436 | obj_desc->field.access_length = info->access_length; |
437 | |
438 | if (info->connection_node) { |
439 | second_desc = info->connection_node->object; |
440 | if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) { |
441 | status = |
442 | acpi_ds_get_buffer_arguments(obj_desc: second_desc); |
443 | if (ACPI_FAILURE(status)) { |
444 | acpi_ut_delete_object_desc(object: obj_desc); |
445 | return_ACPI_STATUS(status); |
446 | } |
447 | } |
448 | |
449 | obj_desc->field.resource_buffer = |
450 | second_desc->buffer.pointer; |
451 | obj_desc->field.resource_length = |
452 | (u16)second_desc->buffer.length; |
453 | } else if (info->resource_buffer) { |
454 | obj_desc->field.resource_buffer = info->resource_buffer; |
455 | obj_desc->field.resource_length = info->resource_length; |
456 | } |
457 | |
458 | obj_desc->field.pin_number_index = info->pin_number_index; |
459 | |
460 | /* Allow full data read from EC address space */ |
461 | |
462 | if ((obj_desc->field.region_obj->region.space_id == |
463 | ACPI_ADR_SPACE_EC) |
464 | && (obj_desc->common_field.bit_length > 8)) { |
465 | access_byte_width = |
466 | ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field. |
467 | bit_length); |
468 | |
469 | /* Maximum byte width supported is 255 */ |
470 | |
471 | if (access_byte_width < 256) { |
472 | obj_desc->common_field.access_byte_width = |
473 | (u8)access_byte_width; |
474 | } |
475 | } |
476 | ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
477 | "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n" , |
478 | obj_desc->field.start_field_bit_offset, |
479 | obj_desc->field.base_byte_offset, |
480 | obj_desc->field.access_byte_width, |
481 | obj_desc->field.region_obj)); |
482 | break; |
483 | |
484 | case ACPI_TYPE_LOCAL_BANK_FIELD: |
485 | |
486 | obj_desc->bank_field.value = info->bank_value; |
487 | obj_desc->bank_field.region_obj = |
488 | acpi_ns_get_attached_object(node: info->region_node); |
489 | obj_desc->bank_field.bank_obj = |
490 | acpi_ns_get_attached_object(node: info->register_node); |
491 | |
492 | /* An additional reference for the attached objects */ |
493 | |
494 | acpi_ut_add_reference(object: obj_desc->bank_field.region_obj); |
495 | acpi_ut_add_reference(object: obj_desc->bank_field.bank_obj); |
496 | |
497 | ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
498 | "Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n" , |
499 | obj_desc->bank_field.start_field_bit_offset, |
500 | obj_desc->bank_field.base_byte_offset, |
501 | obj_desc->field.access_byte_width, |
502 | obj_desc->bank_field.region_obj, |
503 | obj_desc->bank_field.bank_obj)); |
504 | |
505 | /* |
506 | * Remember location in AML stream of the field unit |
507 | * opcode and operands -- since the bank_value |
508 | * operands must be evaluated. |
509 | */ |
510 | second_desc = obj_desc->common.next_object; |
511 | second_desc->extra.aml_start = |
512 | ACPI_CAST_PTR(union acpi_parse_object, |
513 | info->data_register_node)->named.data; |
514 | second_desc->extra.aml_length = |
515 | ACPI_CAST_PTR(union acpi_parse_object, |
516 | info->data_register_node)->named.length; |
517 | |
518 | break; |
519 | |
520 | case ACPI_TYPE_LOCAL_INDEX_FIELD: |
521 | |
522 | /* Get the Index and Data registers */ |
523 | |
524 | obj_desc->index_field.index_obj = |
525 | acpi_ns_get_attached_object(node: info->register_node); |
526 | obj_desc->index_field.data_obj = |
527 | acpi_ns_get_attached_object(node: info->data_register_node); |
528 | |
529 | if (!obj_desc->index_field.data_obj |
530 | || !obj_desc->index_field.index_obj) { |
531 | ACPI_ERROR((AE_INFO, |
532 | "Null Index Object during field prep" )); |
533 | acpi_ut_delete_object_desc(object: obj_desc); |
534 | return_ACPI_STATUS(AE_AML_INTERNAL); |
535 | } |
536 | |
537 | /* An additional reference for the attached objects */ |
538 | |
539 | acpi_ut_add_reference(object: obj_desc->index_field.data_obj); |
540 | acpi_ut_add_reference(object: obj_desc->index_field.index_obj); |
541 | |
542 | /* |
543 | * April 2006: Changed to match MS behavior |
544 | * |
545 | * The value written to the Index register is the byte offset of the |
546 | * target field in units of the granularity of the index_field |
547 | * |
548 | * Previously, the value was calculated as an index in terms of the |
549 | * width of the Data register, as below: |
550 | * |
551 | * obj_desc->index_field.Value = (u32) |
552 | * (Info->field_bit_position / ACPI_MUL_8 ( |
553 | * obj_desc->Field.access_byte_width)); |
554 | * |
555 | * February 2006: Tried value as a byte offset: |
556 | * obj_desc->index_field.Value = (u32) |
557 | * ACPI_DIV_8 (Info->field_bit_position); |
558 | */ |
559 | obj_desc->index_field.value = |
560 | (u32) ACPI_ROUND_DOWN(ACPI_DIV_8(info->field_bit_position), |
561 | obj_desc->index_field. |
562 | access_byte_width); |
563 | |
564 | ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
565 | "IndexField: BitOff %X, Off %X, Value %X, " |
566 | "Gran %X, Index %p, Data %p\n" , |
567 | obj_desc->index_field.start_field_bit_offset, |
568 | obj_desc->index_field.base_byte_offset, |
569 | obj_desc->index_field.value, |
570 | obj_desc->field.access_byte_width, |
571 | obj_desc->index_field.index_obj, |
572 | obj_desc->index_field.data_obj)); |
573 | break; |
574 | |
575 | default: |
576 | |
577 | /* No other types should get here */ |
578 | |
579 | break; |
580 | } |
581 | |
582 | /* |
583 | * Store the constructed descriptor (obj_desc) into the parent Node, |
584 | * preserving the current type of that named_obj. |
585 | */ |
586 | status = |
587 | acpi_ns_attach_object(node: info->field_node, object: obj_desc, |
588 | type: acpi_ns_get_type(node: info->field_node)); |
589 | |
590 | ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
591 | "Set NamedObj %p [%4.4s], ObjDesc %p\n" , |
592 | info->field_node, |
593 | acpi_ut_get_node_name(info->field_node), obj_desc)); |
594 | |
595 | /* Remove local reference to the object */ |
596 | |
597 | acpi_ut_remove_reference(object: obj_desc); |
598 | return_ACPI_STATUS(status); |
599 | } |
600 | |