Esempio n. 1
0
acpi_status
acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
			   void *buffer, u32 buffer_length)
{
	acpi_status status;
	u64 raw_datum;
	u64 merged_datum;
	u32 field_offset = 0;
	u32 buffer_offset = 0;
	u32 buffer_tail_bits;
	u32 datum_count;
	u32 field_datum_count;
	u32 access_bit_width;
	u32 i;

	ACPI_FUNCTION_TRACE(ex_extract_from_field);

	/* Validate target buffer and clear it */

	if (buffer_length <
	    ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length)) {
		ACPI_ERROR((AE_INFO,
			    "Field size %u (bits) is too large for buffer (%u)",
			    obj_desc->common_field.bit_length, buffer_length));

		return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
	}

	ACPI_MEMSET(buffer, 0, buffer_length);
	access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width);

	/* Handle the simple case here */

	if ((obj_desc->common_field.start_field_bit_offset == 0) &&
	    (obj_desc->common_field.bit_length == access_bit_width)) {
		status = acpi_ex_field_datum_io(obj_desc, 0, buffer, ACPI_READ);
		return_ACPI_STATUS(status);
	}

/* TBD: Move to common setup code */

	/* Field algorithm is limited to sizeof(u64), truncate if needed */

	if (obj_desc->common_field.access_byte_width > sizeof(u64)) {
		obj_desc->common_field.access_byte_width = sizeof(u64);
		access_bit_width = sizeof(u64) * 8;
	}

	/* Compute the number of datums (access width data items) */

	datum_count =
	    ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
			     access_bit_width);

	field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
					     obj_desc->common_field.
					     start_field_bit_offset,
					     access_bit_width);

	/* Priming read from the field */

	status =
	    acpi_ex_field_datum_io(obj_desc, field_offset, &raw_datum,
				   ACPI_READ);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}
	merged_datum =
	    raw_datum >> obj_desc->common_field.start_field_bit_offset;

	/* Read the rest of the field */

	for (i = 1; i < field_datum_count; i++) {

		/* Get next input datum from the field */

		field_offset += obj_desc->common_field.access_byte_width;
		status = acpi_ex_field_datum_io(obj_desc, field_offset,
						&raw_datum, ACPI_READ);
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
		}

		/*
		 * Merge with previous datum if necessary.
		 *
		 * Note: Before the shift, check if the shift value will be larger than
		 * the integer size. If so, there is no need to perform the operation.
		 * This avoids the differences in behavior between different compilers
		 * concerning shift values larger than the target data width.
		 */
		if (access_bit_width -
		    obj_desc->common_field.start_field_bit_offset <
		    ACPI_INTEGER_BIT_SIZE) {
			merged_datum |=
			    raw_datum << (access_bit_width -
					  obj_desc->common_field.
					  start_field_bit_offset);
		}

		if (i == datum_count) {
			break;
		}

		/* Write merged datum to target buffer */

		ACPI_MEMCPY(((char *)buffer) + buffer_offset, &merged_datum,
			    ACPI_MIN(obj_desc->common_field.access_byte_width,
				     buffer_length - buffer_offset));

		buffer_offset += obj_desc->common_field.access_byte_width;
		merged_datum =
		    raw_datum >> obj_desc->common_field.start_field_bit_offset;
	}

	/* Mask off any extra bits in the last datum */

	buffer_tail_bits = obj_desc->common_field.bit_length % access_bit_width;
	if (buffer_tail_bits) {
		merged_datum &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits);
	}

	/* Write the last datum to the buffer */

	ACPI_MEMCPY(((char *)buffer) + buffer_offset, &merged_datum,
		    ACPI_MIN(obj_desc->common_field.access_byte_width,
			     buffer_length - buffer_offset));

	return_ACPI_STATUS(AE_OK);
}
Esempio n. 2
0
acpi_status
acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc,
			       u64 mask,
			       u64 field_value, u32 field_datum_byte_offset)
{
	acpi_status status = AE_OK;
	u64 merged_value;
	u64 current_value;

	ACPI_FUNCTION_TRACE_U32(ex_write_with_update_rule, mask);

	/* Start with the new bits  */

	merged_value = field_value;

	/* If the mask is all ones, we don't need to worry about the update rule */

	if (mask != ACPI_UINT64_MAX) {

		/* Decode the update rule */

		switch (obj_desc->common_field.
			field_flags & AML_FIELD_UPDATE_RULE_MASK) {
		case AML_FIELD_UPDATE_PRESERVE:
			/*
			 * Check if update rule needs to be applied (not if mask is all
			 * ones)  The left shift drops the bits we want to ignore.
			 */
			if ((~mask << (ACPI_MUL_8(sizeof(mask)) -
				       ACPI_MUL_8(obj_desc->common_field.
						  access_byte_width))) != 0) {
				/*
				 * Read the current contents of the byte/word/dword containing
				 * the field, and merge with the new field value.
				 */
				status =
				    acpi_ex_field_datum_io(obj_desc,
							   field_datum_byte_offset,
							   &current_value,
							   ACPI_READ);
				if (ACPI_FAILURE(status)) {
					return_ACPI_STATUS(status);
				}

				merged_value |= (current_value & ~mask);
			}
			break;

		case AML_FIELD_UPDATE_WRITE_AS_ONES:

			/* Set positions outside the field to all ones */

			merged_value |= ~mask;
			break;

		case AML_FIELD_UPDATE_WRITE_AS_ZEROS:

			/* Set positions outside the field to all zeros */

			merged_value &= mask;
			break;

		default:

			ACPI_ERROR((AE_INFO,
				    "Unknown UpdateRule value: 0x%X",
				    (obj_desc->common_field.
				     field_flags &
				     AML_FIELD_UPDATE_RULE_MASK)));
			return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
		}
	}

	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
			  "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
			  ACPI_FORMAT_UINT64(mask),
			  field_datum_byte_offset,
			  obj_desc->common_field.access_byte_width,
			  ACPI_FORMAT_UINT64(field_value),
			  ACPI_FORMAT_UINT64(merged_value)));

	/* Write the merged value */

	status = acpi_ex_field_datum_io(obj_desc, field_datum_byte_offset,
					&merged_value, ACPI_WRITE);

	return_ACPI_STATUS(status);
}
Esempio n. 3
0
acpi_status
acpi_ex_extract_from_field (
	union acpi_operand_object       *obj_desc,
	void                            *buffer,
	u32                             buffer_length)
{
	acpi_status                     status;
	acpi_integer                    raw_datum;
	acpi_integer                    merged_datum;
	u32                             field_offset = 0;
	u32                             buffer_offset = 0;
	u32                             buffer_tail_bits;
	u32                             datum_count;
	u32                             field_datum_count;
	u32                             i;


	ACPI_FUNCTION_TRACE ("ex_extract_from_field");


	/* Validate target buffer and clear it */

	if (buffer_length < ACPI_ROUND_BITS_UP_TO_BYTES (
			 obj_desc->common_field.bit_length)) {
		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
			"Field size %X (bits) is too large for buffer (%X)\n",
			obj_desc->common_field.bit_length, buffer_length));

		return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
	}
	ACPI_MEMSET (buffer, 0, buffer_length);

	/* Compute the number of datums (access width data items) */

	datum_count = ACPI_ROUND_UP_TO (
			   obj_desc->common_field.bit_length,
			   obj_desc->common_field.access_bit_width);
	field_datum_count = ACPI_ROUND_UP_TO (
			   obj_desc->common_field.bit_length +
			   obj_desc->common_field.start_field_bit_offset,
			   obj_desc->common_field.access_bit_width);

	/* Priming read from the field */

	status = acpi_ex_field_datum_io (obj_desc, field_offset, &raw_datum, ACPI_READ);
	if (ACPI_FAILURE (status)) {
		return_ACPI_STATUS (status);
	}
	merged_datum = raw_datum >> obj_desc->common_field.start_field_bit_offset;

	/* Read the rest of the field */

	for (i = 1; i < field_datum_count; i++) {
		/* Get next input datum from the field */

		field_offset += obj_desc->common_field.access_byte_width;
		status = acpi_ex_field_datum_io (obj_desc, field_offset,
				  &raw_datum, ACPI_READ);
		if (ACPI_FAILURE (status)) {
			return_ACPI_STATUS (status);
		}

		/* Merge with previous datum if necessary */

		merged_datum |= raw_datum <<
			(obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset);

		if (i == datum_count) {
			break;
		}

		/* Write merged datum to target buffer */

		ACPI_MEMCPY (((char *) buffer) + buffer_offset, &merged_datum,
			ACPI_MIN(obj_desc->common_field.access_byte_width,
					 buffer_length - buffer_offset));

		buffer_offset += obj_desc->common_field.access_byte_width;
		merged_datum = raw_datum >> obj_desc->common_field.start_field_bit_offset;
	}

	/* Mask off any extra bits in the last datum */

	buffer_tail_bits = obj_desc->common_field.bit_length % obj_desc->common_field.access_bit_width;
	if (buffer_tail_bits) {
		merged_datum &= ACPI_MASK_BITS_ABOVE (buffer_tail_bits);
	}

	/* Write the last datum to the buffer */

	ACPI_MEMCPY (((char *) buffer) + buffer_offset, &merged_datum,
		ACPI_MIN(obj_desc->common_field.access_byte_width,
				 buffer_length - buffer_offset));

	return_ACPI_STATUS (AE_OK);
}
Esempio n. 4
0
acpi_status
acpi_ex_extract_from_field (
	union acpi_operand_object       *obj_desc,
	void                            *buffer,
	u32                             buffer_length)
{
	acpi_status                     status;
	u32                             field_datum_byte_offset;
	u32                             datum_offset;
	acpi_integer                    previous_raw_datum;
	acpi_integer                    this_raw_datum = 0;
	acpi_integer                    merged_datum = 0;
	u32                             byte_field_length;
	u32                             datum_count;


	ACPI_FUNCTION_TRACE ("ex_extract_from_field");


	/*
	 * The field must fit within the caller's buffer
	 */
	byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length);
	if (byte_field_length > buffer_length) {
		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
			"Field size %X (bytes) too large for buffer (%X)\n",
			byte_field_length, buffer_length));

		return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
	}

	/* Convert field byte count to datum count, round up if necessary */

	datum_count = ACPI_ROUND_UP_TO (byte_field_length,
			   obj_desc->common_field.access_byte_width);

	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
		"byte_len %X, datum_len %X, byte_gran %X\n",
		byte_field_length, datum_count,obj_desc->common_field.access_byte_width));

	/*
	 * Clear the caller's buffer (the whole buffer length as given)
	 * This is very important, especially in the cases where a byte is read,
	 * but the buffer is really a u32 (4 bytes).
	 */
	ACPI_MEMSET (buffer, 0, buffer_length);

	/* Read the first raw datum to prime the loop */

	field_datum_byte_offset = 0;
	datum_offset= 0;

	status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset,
			  &previous_raw_datum, ACPI_READ);
	if (ACPI_FAILURE (status)) {
		return_ACPI_STATUS (status);
	}


	/* We might actually be done if the request fits in one datum */

	if ((datum_count == 1) &&
		(obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM)) {
		/* 1) Shift the valid data bits down to start at bit 0 */

		merged_datum = (previous_raw_datum >> obj_desc->common_field.start_field_bit_offset);

		/* 2) Mask off any upper unused bits (bits not part of the field) */

		if (obj_desc->common_field.end_buffer_valid_bits) {
			merged_datum &= ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits);
		}

		/* Store the datum to the caller buffer */

		acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length,
				obj_desc->common_field.access_byte_width, datum_offset);

		return_ACPI_STATUS (AE_OK);
	}
Esempio n. 5
0
acpi_status
acpi_ex_extract_from_field (
	union acpi_operand_object       *obj_desc,
	void                            *buffer,
	u32                             buffer_length)
{
	acpi_status                     status;
	u32                             field_datum_byte_offset;
	u32                             buffer_datum_offset;
	acpi_integer                    previous_raw_datum = 0;
	acpi_integer                    this_raw_datum = 0;
	acpi_integer                    merged_datum = 0;
	u32                             byte_field_length;
	u32                             datum_count;
	u32                             i;


	ACPI_FUNCTION_TRACE ("ex_extract_from_field");


	/*
	 * The field must fit within the caller's buffer
	 */
	byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length);
	if (byte_field_length > buffer_length) {
		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
			"Field size %X (bytes) too large for buffer (%X)\n",
			byte_field_length, buffer_length));

		return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
	}

	/* Convert field byte count to datum count, round up if necessary */

	datum_count = ACPI_ROUND_UP_TO (byte_field_length,
			   obj_desc->common_field.access_byte_width);

	/*
	 * If the field is not aligned on a datum boundary and does not
	 * fit within a single datum, we must read an extra datum.
	 *
	 * We could just split the aligned and non-aligned cases since the
	 * aligned case is so very simple, but this would require more code.
	 */
	if ((obj_desc->common_field.end_field_valid_bits != 0)    &&
		(!(obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM))) {
		datum_count++;
	}

	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
		"byte_len %X, datum_len %X, byte_gran %X\n",
		byte_field_length, datum_count,obj_desc->common_field.access_byte_width));

	/*
	 * Clear the caller's buffer (the whole buffer length as given)
	 * This is very important, especially in the cases where the buffer
	 * is longer than the size of the field.
	 */
	ACPI_MEMSET (buffer, 0, buffer_length);

	field_datum_byte_offset = 0;
	buffer_datum_offset= 0;

	/* Read the entire field */

	for (i = 0; i < datum_count; i++) {
		status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset,
				  &this_raw_datum, ACPI_READ);
		if (ACPI_FAILURE (status)) {
			return_ACPI_STATUS (status);
		}

		/* We might actually be done if the request fits in one datum */

		if ((datum_count == 1) &&
			(obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM)) {
			/* 1) Shift the valid data bits down to start at bit 0 */

			merged_datum = (this_raw_datum >> obj_desc->common_field.start_field_bit_offset);

			/* 2) Mask off any upper unused bits (bits not part of the field) */

			if (obj_desc->common_field.end_buffer_valid_bits) {
				merged_datum &= ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits);
			}

			/* Store the datum to the caller buffer */

			acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length,
					obj_desc->common_field.access_byte_width, buffer_datum_offset);

			return_ACPI_STATUS (AE_OK);
		}

		/* Special handling for the last datum to ignore extra bits */

		if ((i >= (datum_count -1))          &&
			(obj_desc->common_field.end_field_valid_bits)) {
			/*
			 * This is the last iteration of the loop.  We need to clear
			 * any unused bits (bits that are not part of this field) before
			 * we store the final merged datum into the caller buffer.
			 */
			this_raw_datum &=
				ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits);
		}

		/*
		 * Create the (possibly) merged datum to be stored to the caller buffer
		 */
		if (obj_desc->common_field.start_field_bit_offset == 0) {
			/* Field is not skewed and we can just copy the datum */

			acpi_ex_set_buffer_datum (this_raw_datum, buffer, buffer_length,
					obj_desc->common_field.access_byte_width, buffer_datum_offset);
			buffer_datum_offset++;
		}
		else {
			/* Not aligned -- on the first iteration, just save the datum */

			if (i != 0) {
				/*
				 * Put together the appropriate bits of the two raw data to make a
				 * single complete field datum
				 *
				 * 1) Normalize the first datum down to bit 0
				 */
				merged_datum = (previous_raw_datum >> obj_desc->common_field.start_field_bit_offset);

				/* 2) Insert the second datum "above" the first datum */

				merged_datum |= (this_raw_datum << obj_desc->common_field.datum_valid_bits);

				acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length,
						obj_desc->common_field.access_byte_width, buffer_datum_offset);
				buffer_datum_offset++;
			}

			/*
			 * Save the raw datum that was just acquired since it may contain bits
			 * of the *next* field datum
			 */
			previous_raw_datum = this_raw_datum;
		}