162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: exprep - ACPI AML field prep utilities
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *****************************************************************************/
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <acpi/acpi.h>
1162306a36Sopenharmony_ci#include "accommon.h"
1262306a36Sopenharmony_ci#include "acinterp.h"
1362306a36Sopenharmony_ci#include "amlcode.h"
1462306a36Sopenharmony_ci#include "acnamesp.h"
1562306a36Sopenharmony_ci#include "acdispat.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define _COMPONENT          ACPI_EXECUTER
1862306a36Sopenharmony_ciACPI_MODULE_NAME("exprep")
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* Local prototypes */
2162306a36Sopenharmony_cistatic u32
2262306a36Sopenharmony_ciacpi_ex_decode_field_access(union acpi_operand_object *obj_desc,
2362306a36Sopenharmony_ci			    u8 field_flags, u32 * return_byte_alignment);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#ifdef ACPI_UNDER_DEVELOPMENT
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic u32
2862306a36Sopenharmony_ciacpi_ex_generate_access(u32 field_bit_offset,
2962306a36Sopenharmony_ci			u32 field_bit_length, u32 region_length);
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/*******************************************************************************
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * FUNCTION:    acpi_ex_generate_access
3462306a36Sopenharmony_ci *
3562306a36Sopenharmony_ci * PARAMETERS:  field_bit_offset    - Start of field within parent region/buffer
3662306a36Sopenharmony_ci *              field_bit_length    - Length of field in bits
3762306a36Sopenharmony_ci *              region_length       - Length of parent in bytes
3862306a36Sopenharmony_ci *
3962306a36Sopenharmony_ci * RETURN:      Field granularity (8, 16, 32 or 64) and
4062306a36Sopenharmony_ci *              byte_alignment (1, 2, 3, or 4)
4162306a36Sopenharmony_ci *
4262306a36Sopenharmony_ci * DESCRIPTION: Generate an optimal access width for fields defined with the
4362306a36Sopenharmony_ci *              any_acc keyword.
4462306a36Sopenharmony_ci *
4562306a36Sopenharmony_ci * NOTE: Need to have the region_length in order to check for boundary
4662306a36Sopenharmony_ci *       conditions (end-of-region). However, the region_length is a deferred
4762306a36Sopenharmony_ci *       operation. Therefore, to complete this implementation, the generation
4862306a36Sopenharmony_ci *       of this access width must be deferred until the region length has
4962306a36Sopenharmony_ci *       been evaluated.
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci ******************************************************************************/
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic u32
5462306a36Sopenharmony_ciacpi_ex_generate_access(u32 field_bit_offset,
5562306a36Sopenharmony_ci			u32 field_bit_length, u32 region_length)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	u32 field_byte_length;
5862306a36Sopenharmony_ci	u32 field_byte_offset;
5962306a36Sopenharmony_ci	u32 field_byte_end_offset;
6062306a36Sopenharmony_ci	u32 access_byte_width;
6162306a36Sopenharmony_ci	u32 field_start_offset;
6262306a36Sopenharmony_ci	u32 field_end_offset;
6362306a36Sopenharmony_ci	u32 minimum_access_width = 0xFFFFFFFF;
6462306a36Sopenharmony_ci	u32 minimum_accesses = 0xFFFFFFFF;
6562306a36Sopenharmony_ci	u32 accesses;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ex_generate_access);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* Round Field start offset and length to "minimal" byte boundaries */
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	field_byte_offset = ACPI_DIV_8(ACPI_ROUND_DOWN(field_bit_offset, 8));
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	field_byte_end_offset =
7462306a36Sopenharmony_ci	    ACPI_DIV_8(ACPI_ROUND_UP(field_bit_length + field_bit_offset, 8));
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	field_byte_length = field_byte_end_offset - field_byte_offset;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
7962306a36Sopenharmony_ci			  "Bit length %u, Bit offset %u\n",
8062306a36Sopenharmony_ci			  field_bit_length, field_bit_offset));
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
8362306a36Sopenharmony_ci			  "Byte Length %u, Byte Offset %u, End Offset %u\n",
8462306a36Sopenharmony_ci			  field_byte_length, field_byte_offset,
8562306a36Sopenharmony_ci			  field_byte_end_offset));
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	/*
8862306a36Sopenharmony_ci	 * Iterative search for the maximum access width that is both aligned
8962306a36Sopenharmony_ci	 * and does not go beyond the end of the region
9062306a36Sopenharmony_ci	 *
9162306a36Sopenharmony_ci	 * Start at byte_acc and work upwards to qword_acc max. (1,2,4,8 bytes)
9262306a36Sopenharmony_ci	 */
9362306a36Sopenharmony_ci	for (access_byte_width = 1; access_byte_width <= 8;
9462306a36Sopenharmony_ci	     access_byte_width <<= 1) {
9562306a36Sopenharmony_ci		/*
9662306a36Sopenharmony_ci		 * 1) Round end offset up to next access boundary and make sure that
9762306a36Sopenharmony_ci		 *    this does not go beyond the end of the parent region.
9862306a36Sopenharmony_ci		 * 2) When the Access width is greater than the field_byte_length, we
9962306a36Sopenharmony_ci		 *    are done. (This does not optimize for the perfectly aligned
10062306a36Sopenharmony_ci		 *    case yet).
10162306a36Sopenharmony_ci		 */
10262306a36Sopenharmony_ci		if (ACPI_ROUND_UP(field_byte_end_offset, access_byte_width) <=
10362306a36Sopenharmony_ci		    region_length) {
10462306a36Sopenharmony_ci			field_start_offset =
10562306a36Sopenharmony_ci			    ACPI_ROUND_DOWN(field_byte_offset,
10662306a36Sopenharmony_ci					    access_byte_width) /
10762306a36Sopenharmony_ci			    access_byte_width;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci			field_end_offset =
11062306a36Sopenharmony_ci			    ACPI_ROUND_UP((field_byte_length +
11162306a36Sopenharmony_ci					   field_byte_offset),
11262306a36Sopenharmony_ci					  access_byte_width) /
11362306a36Sopenharmony_ci			    access_byte_width;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci			accesses = field_end_offset - field_start_offset;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci			ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
11862306a36Sopenharmony_ci					  "AccessWidth %u end is within region\n",
11962306a36Sopenharmony_ci					  access_byte_width));
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci			ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
12262306a36Sopenharmony_ci					  "Field Start %u, Field End %u -- requires %u accesses\n",
12362306a36Sopenharmony_ci					  field_start_offset, field_end_offset,
12462306a36Sopenharmony_ci					  accesses));
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci			/* Single access is optimal */
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci			if (accesses <= 1) {
12962306a36Sopenharmony_ci				ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
13062306a36Sopenharmony_ci						  "Entire field can be accessed "
13162306a36Sopenharmony_ci						  "with one operation of size %u\n",
13262306a36Sopenharmony_ci						  access_byte_width));
13362306a36Sopenharmony_ci				return_VALUE(access_byte_width);
13462306a36Sopenharmony_ci			}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci			/*
13762306a36Sopenharmony_ci			 * Fits in the region, but requires more than one read/write.
13862306a36Sopenharmony_ci			 * try the next wider access on next iteration
13962306a36Sopenharmony_ci			 */
14062306a36Sopenharmony_ci			if (accesses < minimum_accesses) {
14162306a36Sopenharmony_ci				minimum_accesses = accesses;
14262306a36Sopenharmony_ci				minimum_access_width = access_byte_width;
14362306a36Sopenharmony_ci			}
14462306a36Sopenharmony_ci		} else {
14562306a36Sopenharmony_ci			ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
14662306a36Sopenharmony_ci					  "AccessWidth %u end is NOT within region\n",
14762306a36Sopenharmony_ci					  access_byte_width));
14862306a36Sopenharmony_ci			if (access_byte_width == 1) {
14962306a36Sopenharmony_ci				ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
15062306a36Sopenharmony_ci						  "Field goes beyond end-of-region!\n"));
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci				/* Field does not fit in the region at all */
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci				return_VALUE(0);
15562306a36Sopenharmony_ci			}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci			/*
15862306a36Sopenharmony_ci			 * This width goes beyond the end-of-region, back off to
15962306a36Sopenharmony_ci			 * previous access
16062306a36Sopenharmony_ci			 */
16162306a36Sopenharmony_ci			ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
16262306a36Sopenharmony_ci					  "Backing off to previous optimal access width of %u\n",
16362306a36Sopenharmony_ci					  minimum_access_width));
16462306a36Sopenharmony_ci			return_VALUE(minimum_access_width);
16562306a36Sopenharmony_ci		}
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	/*
16962306a36Sopenharmony_ci	 * Could not read/write field with one operation,
17062306a36Sopenharmony_ci	 * just use max access width
17162306a36Sopenharmony_ci	 */
17262306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
17362306a36Sopenharmony_ci			  "Cannot access field in one operation, using width 8\n"));
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return_VALUE(8);
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci#endif				/* ACPI_UNDER_DEVELOPMENT */
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci/*******************************************************************************
18062306a36Sopenharmony_ci *
18162306a36Sopenharmony_ci * FUNCTION:    acpi_ex_decode_field_access
18262306a36Sopenharmony_ci *
18362306a36Sopenharmony_ci * PARAMETERS:  obj_desc            - Field object
18462306a36Sopenharmony_ci *              field_flags         - Encoded fieldflags (contains access bits)
18562306a36Sopenharmony_ci *              return_byte_alignment - Where the byte alignment is returned
18662306a36Sopenharmony_ci *
18762306a36Sopenharmony_ci * RETURN:      Field granularity (8, 16, 32 or 64) and
18862306a36Sopenharmony_ci *              byte_alignment (1, 2, 3, or 4)
18962306a36Sopenharmony_ci *
19062306a36Sopenharmony_ci * DESCRIPTION: Decode the access_type bits of a field definition.
19162306a36Sopenharmony_ci *
19262306a36Sopenharmony_ci ******************************************************************************/
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic u32
19562306a36Sopenharmony_ciacpi_ex_decode_field_access(union acpi_operand_object *obj_desc,
19662306a36Sopenharmony_ci			    u8 field_flags, u32 * return_byte_alignment)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	u32 access;
19962306a36Sopenharmony_ci	u32 byte_alignment;
20062306a36Sopenharmony_ci	u32 bit_length;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ex_decode_field_access);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	access = (field_flags & AML_FIELD_ACCESS_TYPE_MASK);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	switch (access) {
20762306a36Sopenharmony_ci	case AML_FIELD_ACCESS_ANY:
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci#ifdef ACPI_UNDER_DEVELOPMENT
21062306a36Sopenharmony_ci		byte_alignment =
21162306a36Sopenharmony_ci		    acpi_ex_generate_access(obj_desc->common_field.
21262306a36Sopenharmony_ci					    start_field_bit_offset,
21362306a36Sopenharmony_ci					    obj_desc->common_field.bit_length,
21462306a36Sopenharmony_ci					    0xFFFFFFFF
21562306a36Sopenharmony_ci					    /* Temp until we pass region_length as parameter */
21662306a36Sopenharmony_ci		    );
21762306a36Sopenharmony_ci		bit_length = byte_alignment * 8;
21862306a36Sopenharmony_ci#endif
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci		byte_alignment = 1;
22162306a36Sopenharmony_ci		bit_length = 8;
22262306a36Sopenharmony_ci		break;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	case AML_FIELD_ACCESS_BYTE:
22562306a36Sopenharmony_ci	case AML_FIELD_ACCESS_BUFFER:	/* ACPI 2.0 (SMBus Buffer) */
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci		byte_alignment = 1;
22862306a36Sopenharmony_ci		bit_length = 8;
22962306a36Sopenharmony_ci		break;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	case AML_FIELD_ACCESS_WORD:
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci		byte_alignment = 2;
23462306a36Sopenharmony_ci		bit_length = 16;
23562306a36Sopenharmony_ci		break;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	case AML_FIELD_ACCESS_DWORD:
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci		byte_alignment = 4;
24062306a36Sopenharmony_ci		bit_length = 32;
24162306a36Sopenharmony_ci		break;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	case AML_FIELD_ACCESS_QWORD:	/* ACPI 2.0 */
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci		byte_alignment = 8;
24662306a36Sopenharmony_ci		bit_length = 64;
24762306a36Sopenharmony_ci		break;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	default:
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci		/* Invalid field access type */
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "Unknown field access type 0x%X", access));
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci		return_UINT32(0);
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
25962306a36Sopenharmony_ci		/*
26062306a36Sopenharmony_ci		 * buffer_field access can be on any byte boundary, so the
26162306a36Sopenharmony_ci		 * byte_alignment is always 1 byte -- regardless of any byte_alignment
26262306a36Sopenharmony_ci		 * implied by the field access type.
26362306a36Sopenharmony_ci		 */
26462306a36Sopenharmony_ci		byte_alignment = 1;
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	*return_byte_alignment = byte_alignment;
26862306a36Sopenharmony_ci	return_UINT32(bit_length);
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci/*******************************************************************************
27262306a36Sopenharmony_ci *
27362306a36Sopenharmony_ci * FUNCTION:    acpi_ex_prep_common_field_object
27462306a36Sopenharmony_ci *
27562306a36Sopenharmony_ci * PARAMETERS:  obj_desc            - The field object
27662306a36Sopenharmony_ci *              field_flags         - Access, lock_rule, and update_rule.
27762306a36Sopenharmony_ci *                                    The format of a field_flag is described
27862306a36Sopenharmony_ci *                                    in the ACPI specification
27962306a36Sopenharmony_ci *              field_attribute     - Special attributes (not used)
28062306a36Sopenharmony_ci *              field_bit_position  - Field start position
28162306a36Sopenharmony_ci *              field_bit_length    - Field length in number of bits
28262306a36Sopenharmony_ci *
28362306a36Sopenharmony_ci * RETURN:      Status
28462306a36Sopenharmony_ci *
28562306a36Sopenharmony_ci * DESCRIPTION: Initialize the areas of the field object that are common
28662306a36Sopenharmony_ci *              to the various types of fields. Note: This is very "sensitive"
28762306a36Sopenharmony_ci *              code because we are solving the general case for field
28862306a36Sopenharmony_ci *              alignment.
28962306a36Sopenharmony_ci *
29062306a36Sopenharmony_ci ******************************************************************************/
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ciacpi_status
29362306a36Sopenharmony_ciacpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc,
29462306a36Sopenharmony_ci				 u8 field_flags,
29562306a36Sopenharmony_ci				 u8 field_attribute,
29662306a36Sopenharmony_ci				 u32 field_bit_position, u32 field_bit_length)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	u32 access_bit_width;
29962306a36Sopenharmony_ci	u32 byte_alignment;
30062306a36Sopenharmony_ci	u32 nearest_byte_address;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ex_prep_common_field_object);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	/*
30562306a36Sopenharmony_ci	 * Note: the structure being initialized is the
30662306a36Sopenharmony_ci	 * ACPI_COMMON_FIELD_INFO;  No structure fields outside of the common
30762306a36Sopenharmony_ci	 * area are initialized by this procedure.
30862306a36Sopenharmony_ci	 */
30962306a36Sopenharmony_ci	obj_desc->common_field.field_flags = field_flags;
31062306a36Sopenharmony_ci	obj_desc->common_field.attribute = field_attribute;
31162306a36Sopenharmony_ci	obj_desc->common_field.bit_length = field_bit_length;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	/*
31462306a36Sopenharmony_ci	 * Decode the access type so we can compute offsets. The access type gives
31562306a36Sopenharmony_ci	 * two pieces of information - the width of each field access and the
31662306a36Sopenharmony_ci	 * necessary byte_alignment (address granularity) of the access.
31762306a36Sopenharmony_ci	 *
31862306a36Sopenharmony_ci	 * For any_acc, the access_bit_width is the largest width that is both
31962306a36Sopenharmony_ci	 * necessary and possible in an attempt to access the whole field in one
32062306a36Sopenharmony_ci	 * I/O operation. However, for any_acc, the byte_alignment is always one
32162306a36Sopenharmony_ci	 * byte.
32262306a36Sopenharmony_ci	 *
32362306a36Sopenharmony_ci	 * For all Buffer Fields, the byte_alignment is always one byte.
32462306a36Sopenharmony_ci	 *
32562306a36Sopenharmony_ci	 * For all other access types (Byte, Word, Dword, Qword), the Bitwidth is
32662306a36Sopenharmony_ci	 * the same (equivalent) as the byte_alignment.
32762306a36Sopenharmony_ci	 */
32862306a36Sopenharmony_ci	access_bit_width =
32962306a36Sopenharmony_ci	    acpi_ex_decode_field_access(obj_desc, field_flags, &byte_alignment);
33062306a36Sopenharmony_ci	if (!access_bit_width) {
33162306a36Sopenharmony_ci		return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	/* Setup width (access granularity) fields (values are: 1, 2, 4, 8) */
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	obj_desc->common_field.access_byte_width = (u8)
33762306a36Sopenharmony_ci	    ACPI_DIV_8(access_bit_width);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	/*
34062306a36Sopenharmony_ci	 * base_byte_offset is the address of the start of the field within the
34162306a36Sopenharmony_ci	 * region. It is the byte address of the first *datum* (field-width data
34262306a36Sopenharmony_ci	 * unit) of the field. (i.e., the first datum that contains at least the
34362306a36Sopenharmony_ci	 * first *bit* of the field.)
34462306a36Sopenharmony_ci	 *
34562306a36Sopenharmony_ci	 * Note: byte_alignment is always either equal to the access_bit_width or 8
34662306a36Sopenharmony_ci	 * (Byte access), and it defines the addressing granularity of the parent
34762306a36Sopenharmony_ci	 * region or buffer.
34862306a36Sopenharmony_ci	 */
34962306a36Sopenharmony_ci	nearest_byte_address =
35062306a36Sopenharmony_ci	    ACPI_ROUND_BITS_DOWN_TO_BYTES(field_bit_position);
35162306a36Sopenharmony_ci	obj_desc->common_field.base_byte_offset = (u32)
35262306a36Sopenharmony_ci	    ACPI_ROUND_DOWN(nearest_byte_address, byte_alignment);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	/*
35562306a36Sopenharmony_ci	 * start_field_bit_offset is the offset of the first bit of the field within
35662306a36Sopenharmony_ci	 * a field datum.
35762306a36Sopenharmony_ci	 */
35862306a36Sopenharmony_ci	obj_desc->common_field.start_field_bit_offset = (u8)
35962306a36Sopenharmony_ci	    (field_bit_position -
36062306a36Sopenharmony_ci	     ACPI_MUL_8(obj_desc->common_field.base_byte_offset));
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci/*******************************************************************************
36662306a36Sopenharmony_ci *
36762306a36Sopenharmony_ci * FUNCTION:    acpi_ex_prep_field_value
36862306a36Sopenharmony_ci *
36962306a36Sopenharmony_ci * PARAMETERS:  info    - Contains all field creation info
37062306a36Sopenharmony_ci *
37162306a36Sopenharmony_ci * RETURN:      Status
37262306a36Sopenharmony_ci *
37362306a36Sopenharmony_ci * DESCRIPTION: Construct an object of type union acpi_operand_object with a
37462306a36Sopenharmony_ci *              subtype of def_field and connect it to the parent Node.
37562306a36Sopenharmony_ci *
37662306a36Sopenharmony_ci ******************************************************************************/
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ciacpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	union acpi_operand_object *obj_desc;
38162306a36Sopenharmony_ci	union acpi_operand_object *second_desc = NULL;
38262306a36Sopenharmony_ci	acpi_status status;
38362306a36Sopenharmony_ci	u32 access_byte_width;
38462306a36Sopenharmony_ci	u32 type;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ex_prep_field_value);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	/* Parameter validation */
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	if (info->field_type != ACPI_TYPE_LOCAL_INDEX_FIELD) {
39162306a36Sopenharmony_ci		if (!info->region_node) {
39262306a36Sopenharmony_ci			ACPI_ERROR((AE_INFO, "Null RegionNode"));
39362306a36Sopenharmony_ci			return_ACPI_STATUS(AE_AML_NO_OPERAND);
39462306a36Sopenharmony_ci		}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci		type = acpi_ns_get_type(info->region_node);
39762306a36Sopenharmony_ci		if (type != ACPI_TYPE_REGION) {
39862306a36Sopenharmony_ci			ACPI_ERROR((AE_INFO,
39962306a36Sopenharmony_ci				    "Needed Region, found type 0x%X (%s)", type,
40062306a36Sopenharmony_ci				    acpi_ut_get_type_name(type)));
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci			return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
40362306a36Sopenharmony_ci		}
40462306a36Sopenharmony_ci	}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	/* Allocate a new field object */
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	obj_desc = acpi_ut_create_internal_object(info->field_type);
40962306a36Sopenharmony_ci	if (!obj_desc) {
41062306a36Sopenharmony_ci		return_ACPI_STATUS(AE_NO_MEMORY);
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	/* Initialize areas of the object that are common to all fields */
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	obj_desc->common_field.node = info->field_node;
41662306a36Sopenharmony_ci	status = acpi_ex_prep_common_field_object(obj_desc,
41762306a36Sopenharmony_ci						  info->field_flags,
41862306a36Sopenharmony_ci						  info->attribute,
41962306a36Sopenharmony_ci						  info->field_bit_position,
42062306a36Sopenharmony_ci						  info->field_bit_length);
42162306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
42262306a36Sopenharmony_ci		acpi_ut_delete_object_desc(obj_desc);
42362306a36Sopenharmony_ci		return_ACPI_STATUS(status);
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	/* Initialize areas of the object that are specific to the field type */
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	switch (info->field_type) {
42962306a36Sopenharmony_ci	case ACPI_TYPE_LOCAL_REGION_FIELD:
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci		obj_desc->field.region_obj =
43262306a36Sopenharmony_ci		    acpi_ns_get_attached_object(info->region_node);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		/* Fields specific to generic_serial_bus fields */
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci		obj_desc->field.access_length = info->access_length;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci		if (info->connection_node) {
43962306a36Sopenharmony_ci			second_desc = info->connection_node->object;
44062306a36Sopenharmony_ci			if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) {
44162306a36Sopenharmony_ci				status =
44262306a36Sopenharmony_ci				    acpi_ds_get_buffer_arguments(second_desc);
44362306a36Sopenharmony_ci				if (ACPI_FAILURE(status)) {
44462306a36Sopenharmony_ci					acpi_ut_delete_object_desc(obj_desc);
44562306a36Sopenharmony_ci					return_ACPI_STATUS(status);
44662306a36Sopenharmony_ci				}
44762306a36Sopenharmony_ci			}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci			obj_desc->field.resource_buffer =
45062306a36Sopenharmony_ci			    second_desc->buffer.pointer;
45162306a36Sopenharmony_ci			obj_desc->field.resource_length =
45262306a36Sopenharmony_ci			    (u16)second_desc->buffer.length;
45362306a36Sopenharmony_ci		} else if (info->resource_buffer) {
45462306a36Sopenharmony_ci			obj_desc->field.resource_buffer = info->resource_buffer;
45562306a36Sopenharmony_ci			obj_desc->field.resource_length = info->resource_length;
45662306a36Sopenharmony_ci		}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci		obj_desc->field.pin_number_index = info->pin_number_index;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci		/* Allow full data read from EC address space */
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci		if ((obj_desc->field.region_obj->region.space_id ==
46362306a36Sopenharmony_ci		     ACPI_ADR_SPACE_EC)
46462306a36Sopenharmony_ci		    && (obj_desc->common_field.bit_length > 8)) {
46562306a36Sopenharmony_ci			access_byte_width =
46662306a36Sopenharmony_ci			    ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.
46762306a36Sopenharmony_ci							bit_length);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci			/* Maximum byte width supported is 255 */
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci			if (access_byte_width < 256) {
47262306a36Sopenharmony_ci				obj_desc->common_field.access_byte_width =
47362306a36Sopenharmony_ci				    (u8)access_byte_width;
47462306a36Sopenharmony_ci			}
47562306a36Sopenharmony_ci		}
47662306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
47762306a36Sopenharmony_ci				  "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n",
47862306a36Sopenharmony_ci				  obj_desc->field.start_field_bit_offset,
47962306a36Sopenharmony_ci				  obj_desc->field.base_byte_offset,
48062306a36Sopenharmony_ci				  obj_desc->field.access_byte_width,
48162306a36Sopenharmony_ci				  obj_desc->field.region_obj));
48262306a36Sopenharmony_ci		break;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	case ACPI_TYPE_LOCAL_BANK_FIELD:
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci		obj_desc->bank_field.value = info->bank_value;
48762306a36Sopenharmony_ci		obj_desc->bank_field.region_obj =
48862306a36Sopenharmony_ci		    acpi_ns_get_attached_object(info->region_node);
48962306a36Sopenharmony_ci		obj_desc->bank_field.bank_obj =
49062306a36Sopenharmony_ci		    acpi_ns_get_attached_object(info->register_node);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci		/* An additional reference for the attached objects */
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci		acpi_ut_add_reference(obj_desc->bank_field.region_obj);
49562306a36Sopenharmony_ci		acpi_ut_add_reference(obj_desc->bank_field.bank_obj);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
49862306a36Sopenharmony_ci				  "Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n",
49962306a36Sopenharmony_ci				  obj_desc->bank_field.start_field_bit_offset,
50062306a36Sopenharmony_ci				  obj_desc->bank_field.base_byte_offset,
50162306a36Sopenharmony_ci				  obj_desc->field.access_byte_width,
50262306a36Sopenharmony_ci				  obj_desc->bank_field.region_obj,
50362306a36Sopenharmony_ci				  obj_desc->bank_field.bank_obj));
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci		/*
50662306a36Sopenharmony_ci		 * Remember location in AML stream of the field unit
50762306a36Sopenharmony_ci		 * opcode and operands -- since the bank_value
50862306a36Sopenharmony_ci		 * operands must be evaluated.
50962306a36Sopenharmony_ci		 */
51062306a36Sopenharmony_ci		second_desc = obj_desc->common.next_object;
51162306a36Sopenharmony_ci		second_desc->extra.aml_start =
51262306a36Sopenharmony_ci		    ACPI_CAST_PTR(union acpi_parse_object,
51362306a36Sopenharmony_ci				  info->data_register_node)->named.data;
51462306a36Sopenharmony_ci		second_desc->extra.aml_length =
51562306a36Sopenharmony_ci		    ACPI_CAST_PTR(union acpi_parse_object,
51662306a36Sopenharmony_ci				  info->data_register_node)->named.length;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci		break;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	case ACPI_TYPE_LOCAL_INDEX_FIELD:
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci		/* Get the Index and Data registers */
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci		obj_desc->index_field.index_obj =
52562306a36Sopenharmony_ci		    acpi_ns_get_attached_object(info->register_node);
52662306a36Sopenharmony_ci		obj_desc->index_field.data_obj =
52762306a36Sopenharmony_ci		    acpi_ns_get_attached_object(info->data_register_node);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci		if (!obj_desc->index_field.data_obj
53062306a36Sopenharmony_ci		    || !obj_desc->index_field.index_obj) {
53162306a36Sopenharmony_ci			ACPI_ERROR((AE_INFO,
53262306a36Sopenharmony_ci				    "Null Index Object during field prep"));
53362306a36Sopenharmony_ci			acpi_ut_delete_object_desc(obj_desc);
53462306a36Sopenharmony_ci			return_ACPI_STATUS(AE_AML_INTERNAL);
53562306a36Sopenharmony_ci		}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci		/* An additional reference for the attached objects */
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci		acpi_ut_add_reference(obj_desc->index_field.data_obj);
54062306a36Sopenharmony_ci		acpi_ut_add_reference(obj_desc->index_field.index_obj);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci		/*
54362306a36Sopenharmony_ci		 * April 2006: Changed to match MS behavior
54462306a36Sopenharmony_ci		 *
54562306a36Sopenharmony_ci		 * The value written to the Index register is the byte offset of the
54662306a36Sopenharmony_ci		 * target field in units of the granularity of the index_field
54762306a36Sopenharmony_ci		 *
54862306a36Sopenharmony_ci		 * Previously, the value was calculated as an index in terms of the
54962306a36Sopenharmony_ci		 * width of the Data register, as below:
55062306a36Sopenharmony_ci		 *
55162306a36Sopenharmony_ci		 *      obj_desc->index_field.Value = (u32)
55262306a36Sopenharmony_ci		 *          (Info->field_bit_position / ACPI_MUL_8 (
55362306a36Sopenharmony_ci		 *              obj_desc->Field.access_byte_width));
55462306a36Sopenharmony_ci		 *
55562306a36Sopenharmony_ci		 * February 2006: Tried value as a byte offset:
55662306a36Sopenharmony_ci		 *      obj_desc->index_field.Value = (u32)
55762306a36Sopenharmony_ci		 *          ACPI_DIV_8 (Info->field_bit_position);
55862306a36Sopenharmony_ci		 */
55962306a36Sopenharmony_ci		obj_desc->index_field.value =
56062306a36Sopenharmony_ci		    (u32) ACPI_ROUND_DOWN(ACPI_DIV_8(info->field_bit_position),
56162306a36Sopenharmony_ci					  obj_desc->index_field.
56262306a36Sopenharmony_ci					  access_byte_width);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
56562306a36Sopenharmony_ci				  "IndexField: BitOff %X, Off %X, Value %X, "
56662306a36Sopenharmony_ci				  "Gran %X, Index %p, Data %p\n",
56762306a36Sopenharmony_ci				  obj_desc->index_field.start_field_bit_offset,
56862306a36Sopenharmony_ci				  obj_desc->index_field.base_byte_offset,
56962306a36Sopenharmony_ci				  obj_desc->index_field.value,
57062306a36Sopenharmony_ci				  obj_desc->field.access_byte_width,
57162306a36Sopenharmony_ci				  obj_desc->index_field.index_obj,
57262306a36Sopenharmony_ci				  obj_desc->index_field.data_obj));
57362306a36Sopenharmony_ci		break;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	default:
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci		/* No other types should get here */
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci		break;
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	/*
58362306a36Sopenharmony_ci	 * Store the constructed descriptor (obj_desc) into the parent Node,
58462306a36Sopenharmony_ci	 * preserving the current type of that named_obj.
58562306a36Sopenharmony_ci	 */
58662306a36Sopenharmony_ci	status =
58762306a36Sopenharmony_ci	    acpi_ns_attach_object(info->field_node, obj_desc,
58862306a36Sopenharmony_ci				  acpi_ns_get_type(info->field_node));
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
59162306a36Sopenharmony_ci			  "Set NamedObj %p [%4.4s], ObjDesc %p\n",
59262306a36Sopenharmony_ci			  info->field_node,
59362306a36Sopenharmony_ci			  acpi_ut_get_node_name(info->field_node), obj_desc));
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	/* Remove local reference to the object */
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	acpi_ut_remove_reference(obj_desc);
59862306a36Sopenharmony_ci	return_ACPI_STATUS(status);
59962306a36Sopenharmony_ci}
600