linux/drivers/acpi/acpica/exprep.c

// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/******************************************************************************
 *
 * Module Name: exprep - ACPI AML field prep utilities
 *
 * Copyright (C) 2000 - 2023, Intel Corp.
 *
 *****************************************************************************/

#include <acpi/acpi.h>
#include "accommon.h"
#include "acinterp.h"
#include "amlcode.h"
#include "acnamesp.h"
#include "acdispat.h"

#define _COMPONENT
ACPI_MODULE_NAME("exprep")

/* Local prototypes */
static u32
acpi_ex_decode_field_access(union acpi_operand_object *obj_desc,
			    u8 field_flags, u32 * return_byte_alignment);

#ifdef ACPI_UNDER_DEVELOPMENT

static u32
acpi_ex_generate_access(u32 field_bit_offset,
			u32 field_bit_length, u32 region_length);

/*******************************************************************************
 *
 * FUNCTION:    acpi_ex_generate_access
 *
 * PARAMETERS:  field_bit_offset    - Start of field within parent region/buffer
 *              field_bit_length    - Length of field in bits
 *              region_length       - Length of parent in bytes
 *
 * RETURN:      Field granularity (8, 16, 32 or 64) and
 *              byte_alignment (1, 2, 3, or 4)
 *
 * DESCRIPTION: Generate an optimal access width for fields defined with the
 *              any_acc keyword.
 *
 * NOTE: Need to have the region_length in order to check for boundary
 *       conditions (end-of-region). However, the region_length is a deferred
 *       operation. Therefore, to complete this implementation, the generation
 *       of this access width must be deferred until the region length has
 *       been evaluated.
 *
 ******************************************************************************/

static u32
acpi_ex_generate_access(u32 field_bit_offset,
			u32 field_bit_length, u32 region_length)
{
	u32 field_byte_length;
	u32 field_byte_offset;
	u32 field_byte_end_offset;
	u32 access_byte_width;
	u32 field_start_offset;
	u32 field_end_offset;
	u32 minimum_access_width = 0xFFFFFFFF;
	u32 minimum_accesses = 0xFFFFFFFF;
	u32 accesses;

	ACPI_FUNCTION_TRACE(ex_generate_access);

	/* Round Field start offset and length to "minimal" byte boundaries */

	field_byte_offset = ACPI_DIV_8(ACPI_ROUND_DOWN(field_bit_offset, 8));

	field_byte_end_offset =
	    ACPI_DIV_8(ACPI_ROUND_UP(field_bit_length + field_bit_offset, 8));

	field_byte_length = field_byte_end_offset - field_byte_offset;

	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
			  "Bit length %u, Bit offset %u\n",
			  field_bit_length, field_bit_offset));

	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
			  "Byte Length %u, Byte Offset %u, End Offset %u\n",
			  field_byte_length, field_byte_offset,
			  field_byte_end_offset));

	/*
	 * Iterative search for the maximum access width that is both aligned
	 * and does not go beyond the end of the region
	 *
	 * Start at byte_acc and work upwards to qword_acc max. (1,2,4,8 bytes)
	 */
	for (access_byte_width = 1; access_byte_width <= 8;
	     access_byte_width <<= 1) {
		/*
		 * 1) Round end offset up to next access boundary and make sure that
		 *    this does not go beyond the end of the parent region.
		 * 2) When the Access width is greater than the field_byte_length, we
		 *    are done. (This does not optimize for the perfectly aligned
		 *    case yet).
		 */
		if (ACPI_ROUND_UP(field_byte_end_offset, access_byte_width) <=
		    region_length) {
			field_start_offset =
			    ACPI_ROUND_DOWN(field_byte_offset,
					    access_byte_width) /
			    access_byte_width;

			field_end_offset =
			    ACPI_ROUND_UP((field_byte_length +
					   field_byte_offset),
					  access_byte_width) /
			    access_byte_width;

			accesses = field_end_offset - field_start_offset;

			ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
					  "AccessWidth %u end is within region\n",
					  access_byte_width));

			ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
					  "Field Start %u, Field End %u -- requires %u accesses\n",
					  field_start_offset, field_end_offset,
					  accesses));

			/* Single access is optimal */

			if (accesses <= 1) {
				ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
						  "Entire field can be accessed "
						  "with one operation of size %u\n",
						  access_byte_width));
				return_VALUE(access_byte_width);
			}

			/*
			 * Fits in the region, but requires more than one read/write.
			 * try the next wider access on next iteration
			 */
			if (accesses < minimum_accesses) {
				minimum_accesses = accesses;
				minimum_access_width = access_byte_width;
			}
		} else {
			ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
					  "AccessWidth %u end is NOT within region\n",
					  access_byte_width));
			if (access_byte_width == 1) {
				ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
						  "Field goes beyond end-of-region!\n"));

				/* Field does not fit in the region at all */

				return_VALUE(0);
			}

			/*
			 * This width goes beyond the end-of-region, back off to
			 * previous access
			 */
			ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
					  "Backing off to previous optimal access width of %u\n",
					  minimum_access_width));
			return_VALUE(minimum_access_width);
		}
	}

	/*
	 * Could not read/write field with one operation,
	 * just use max access width
	 */
	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
			  "Cannot access field in one operation, using width 8\n"));

	return_VALUE(8);
}
#endif				/* ACPI_UNDER_DEVELOPMENT */

/*******************************************************************************
 *
 * FUNCTION:    acpi_ex_decode_field_access
 *
 * PARAMETERS:  obj_desc            - Field object
 *              field_flags         - Encoded fieldflags (contains access bits)
 *              return_byte_alignment - Where the byte alignment is returned
 *
 * RETURN:      Field granularity (8, 16, 32 or 64) and
 *              byte_alignment (1, 2, 3, or 4)
 *
 * DESCRIPTION: Decode the access_type bits of a field definition.
 *
 ******************************************************************************/

static u32
acpi_ex_decode_field_access(union acpi_operand_object *obj_desc,
			    u8 field_flags, u32 * return_byte_alignment)
{}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ex_prep_common_field_object
 *
 * PARAMETERS:  obj_desc            - The field object
 *              field_flags         - Access, lock_rule, and update_rule.
 *                                    The format of a field_flag is described
 *                                    in the ACPI specification
 *              field_attribute     - Special attributes (not used)
 *              field_bit_position  - Field start position
 *              field_bit_length    - Field length in number of bits
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Initialize the areas of the field object that are common
 *              to the various types of fields. Note: This is very "sensitive"
 *              code because we are solving the general case for field
 *              alignment.
 *
 ******************************************************************************/

acpi_status
acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc,
				 u8 field_flags,
				 u8 field_attribute,
				 u32 field_bit_position, u32 field_bit_length)
{}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ex_prep_field_value
 *
 * PARAMETERS:  info    - Contains all field creation info
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Construct an object of type union acpi_operand_object with a
 *              subtype of def_field and connect it to the parent Node.
 *
 ******************************************************************************/

acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
{}