exfield.c 14.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7
/******************************************************************************
 *
 * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
 *
 *****************************************************************************/

/*
8
 * Copyright (C) 2000 - 2014, Intel Corp.
L
Linus Torvalds 已提交
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer,
 *    without modification.
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
 *    substantially similar to the "NO WARRANTY" disclaimer below
 *    ("Disclaimer") and any redistribution must be conditioned upon
 *    including a substantially similar Disclaimer requirement for further
 *    binary redistribution.
 * 3. Neither the names of the above-listed copyright holders nor the names
 *    of any contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * NO WARRANTY
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 */

#include <acpi/acpi.h>
L
Len Brown 已提交
45 46 47
#include "accommon.h"
#include "acdispat.h"
#include "acinterp.h"
48
#include "amlcode.h"
L
Linus Torvalds 已提交
49 50

#define _COMPONENT          ACPI_EXECUTER
L
Len Brown 已提交
51
ACPI_MODULE_NAME("exfield")
L
Linus Torvalds 已提交
52

53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
/* Local prototypes */
static u32
acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length);

/*******************************************************************************
 *
 * FUNCTION:    acpi_get_serial_access_bytes
 *
 * PARAMETERS:  accessor_type   - The type of the protocol indicated by region
 *                                field access attributes
 *              access_length   - The access length of the region field
 *
 * RETURN:      Decoded access length
 *
 * DESCRIPTION: This routine returns the length of the generic_serial_bus
 *              protocol bytes
 *
 ******************************************************************************/

static u32
acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length)
{
	u32 length;

	switch (accessor_type) {
	case AML_FIELD_ATTRIB_QUICK:

		length = 0;
		break;

	case AML_FIELD_ATTRIB_SEND_RCV:
	case AML_FIELD_ATTRIB_BYTE:

		length = 1;
		break;

	case AML_FIELD_ATTRIB_WORD:
	case AML_FIELD_ATTRIB_WORD_CALL:

		length = 2;
		break;

	case AML_FIELD_ATTRIB_MULTIBYTE:
	case AML_FIELD_ATTRIB_RAW_BYTES:
	case AML_FIELD_ATTRIB_RAW_PROCESS:

		length = access_length;
		break;

	case AML_FIELD_ATTRIB_BLOCK:
	case AML_FIELD_ATTRIB_BLOCK_CALL:
	default:

		length = ACPI_GSBUS_BUFFER_SIZE;
		break;
	}

	return (length);
}

L
Linus Torvalds 已提交
113 114 115 116 117 118 119 120 121 122
/*******************************************************************************
 *
 * FUNCTION:    acpi_ex_read_data_from_field
 *
 * PARAMETERS:  walk_state          - Current execution state
 *              obj_desc            - The named field
 *              ret_buffer_desc     - Where the return data object is stored
 *
 * RETURN:      Status
 *
123
 * DESCRIPTION: Read from a named field. Returns either an Integer or a
L
Linus Torvalds 已提交
124 125 126
 *              Buffer, depending on the size of the field.
 *
 ******************************************************************************/
127

L
Linus Torvalds 已提交
128
acpi_status
129
acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state,
L
Len Brown 已提交
130 131
			     union acpi_operand_object *obj_desc,
			     union acpi_operand_object **ret_buffer_desc)
L
Linus Torvalds 已提交
132
{
L
Len Brown 已提交
133 134 135 136
	acpi_status status;
	union acpi_operand_object *buffer_desc;
	acpi_size length;
	void *buffer;
137
	u32 function;
138
	u16 accessor_type;
L
Linus Torvalds 已提交
139

B
Bob Moore 已提交
140
	ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);
L
Linus Torvalds 已提交
141 142 143 144

	/* Parameter validation */

	if (!obj_desc) {
L
Len Brown 已提交
145
		return_ACPI_STATUS(AE_AML_NO_OPERAND);
L
Linus Torvalds 已提交
146
	}
147
	if (!ret_buffer_desc) {
L
Len Brown 已提交
148
		return_ACPI_STATUS(AE_BAD_PARAMETER);
149
	}
L
Linus Torvalds 已提交
150

151
	if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
L
Linus Torvalds 已提交
152 153 154 155 156
		/*
		 * If the buffer_field arguments have not been previously evaluated,
		 * evaluate them now and save the results.
		 */
		if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
L
Len Brown 已提交
157 158 159
			status = acpi_ds_get_buffer_field_arguments(obj_desc);
			if (ACPI_FAILURE(status)) {
				return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
160 161
			}
		}
162 163
	} else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
		   (obj_desc->field.region_obj->region.space_id ==
164 165
		    ACPI_ADR_SPACE_SMBUS
		    || obj_desc->field.region_obj->region.space_id ==
166 167
		    ACPI_ADR_SPACE_GSBUS
		    || obj_desc->field.region_obj->region.space_id ==
168
		    ACPI_ADR_SPACE_IPMI)) {
L
Linus Torvalds 已提交
169
		/*
170
		 * This is an SMBus, GSBus or IPMI read. We must create a buffer to hold
171 172
		 * the data and then directly access the region handler.
		 *
173
		 * Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function
L
Linus Torvalds 已提交
174
		 */
175 176 177 178 179
		if (obj_desc->field.region_obj->region.space_id ==
		    ACPI_ADR_SPACE_SMBUS) {
			length = ACPI_SMBUS_BUFFER_SIZE;
			function =
			    ACPI_READ | (obj_desc->field.attribute << 16);
180 181
		} else if (obj_desc->field.region_obj->region.space_id ==
			   ACPI_ADR_SPACE_GSBUS) {
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
			accessor_type = obj_desc->field.attribute;
			length = acpi_ex_get_serial_access_length(accessor_type,
								  obj_desc->
								  field.
								  access_length);

			/*
			 * Add additional 2 bytes for modeled generic_serial_bus data buffer:
			 * typedef struct {
			 *     BYTEStatus; // Byte 0 of the data buffer
			 *     BYTELength; // Byte 1 of the data buffer
			 *     BYTE[x-1]Data; // Bytes 2-x of the arbitrary length data buffer,
			 * }
			 */
			length += 2;
			function = ACPI_READ | (accessor_type << 16);
198 199 200 201 202 203 204
		} else {	/* IPMI */

			length = ACPI_IPMI_BUFFER_SIZE;
			function = ACPI_READ;
		}

		buffer_desc = acpi_ut_create_buffer_object(length);
L
Linus Torvalds 已提交
205
		if (!buffer_desc) {
L
Len Brown 已提交
206
			return_ACPI_STATUS(AE_NO_MEMORY);
L
Linus Torvalds 已提交
207 208 209 210
		}

		/* Lock entire transaction if requested */

211
		acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
L
Linus Torvalds 已提交
212

213 214
		/* Call the region handler for the read */

L
Len Brown 已提交
215
		status = acpi_ex_access_region(obj_desc, 0,
216
					       ACPI_CAST_PTR(u64,
L
Len Brown 已提交
217 218
							     buffer_desc->
							     buffer.pointer),
219
					       function);
220
		acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
L
Linus Torvalds 已提交
221 222 223 224 225 226
		goto exit;
	}

	/*
	 * Allocate a buffer for the contents of the field.
	 *
227
	 * If the field is larger than the current integer width, create
228
	 * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
L
Linus Torvalds 已提交
229 230 231 232 233
	 * the use of arithmetic operators on the returned value if the
	 * field size is equal or smaller than an Integer.
	 *
	 * Note: Field.length is in bits.
	 */
L
Len Brown 已提交
234 235
	length =
	    (acpi_size) ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length);
L
Linus Torvalds 已提交
236
	if (length > acpi_gbl_integer_byte_width) {
B
Bob Moore 已提交
237

L
Linus Torvalds 已提交
238 239
		/* Field is too large for an Integer, create a Buffer instead */

L
Len Brown 已提交
240
		buffer_desc = acpi_ut_create_buffer_object(length);
L
Linus Torvalds 已提交
241
		if (!buffer_desc) {
L
Len Brown 已提交
242
			return_ACPI_STATUS(AE_NO_MEMORY);
L
Linus Torvalds 已提交
243 244
		}
		buffer = buffer_desc->buffer.pointer;
L
Len Brown 已提交
245
	} else {
L
Linus Torvalds 已提交
246 247
		/* Field will fit within an Integer (normal case) */

248
		buffer_desc = acpi_ut_create_integer_object((u64) 0);
L
Linus Torvalds 已提交
249
		if (!buffer_desc) {
L
Len Brown 已提交
250
			return_ACPI_STATUS(AE_NO_MEMORY);
L
Linus Torvalds 已提交
251 252 253 254 255 256
		}

		length = acpi_gbl_integer_byte_width;
		buffer = &buffer_desc->integer.value;
	}

L
Len Brown 已提交
257
	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
B
Bob Moore 已提交
258
			  "FieldRead [TO]:   Obj %p, Type %X, Buf %p, ByteLen %X\n",
259
			  obj_desc, obj_desc->common.type, buffer,
L
Len Brown 已提交
260 261
			  (u32) length));
	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
B
Bob Moore 已提交
262
			  "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
L
Len Brown 已提交
263 264 265
			  obj_desc->common_field.bit_length,
			  obj_desc->common_field.start_field_bit_offset,
			  obj_desc->common_field.base_byte_offset));
L
Linus Torvalds 已提交
266 267 268

	/* Lock entire transaction if requested */

269
	acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
L
Linus Torvalds 已提交
270 271 272

	/* Read from the field */

L
Len Brown 已提交
273
	status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length);
274
	acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
L
Linus Torvalds 已提交
275

276
exit:
L
Len Brown 已提交
277 278 279
	if (ACPI_FAILURE(status)) {
		acpi_ut_remove_reference(buffer_desc);
	} else {
L
Linus Torvalds 已提交
280 281 282
		*ret_buffer_desc = buffer_desc;
	}

L
Len Brown 已提交
283
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
284 285 286 287 288 289 290 291
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ex_write_data_to_field
 *
 * PARAMETERS:  source_desc         - Contains data to write
 *              obj_desc            - The named field
R
Robert Moore 已提交
292
 *              result_desc         - Where the return value is returned, if any
L
Linus Torvalds 已提交
293 294 295 296 297 298 299 300
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Write to a named field
 *
 ******************************************************************************/

acpi_status
L
Len Brown 已提交
301 302 303
acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
			    union acpi_operand_object *obj_desc,
			    union acpi_operand_object **result_desc)
L
Linus Torvalds 已提交
304
{
L
Len Brown 已提交
305 306 307 308
	acpi_status status;
	u32 length;
	void *buffer;
	union acpi_operand_object *buffer_desc;
309
	u32 function;
310
	u16 accessor_type;
L
Linus Torvalds 已提交
311

B
Bob Moore 已提交
312
	ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc);
L
Linus Torvalds 已提交
313 314 315 316

	/* Parameter validation */

	if (!source_desc || !obj_desc) {
L
Len Brown 已提交
317
		return_ACPI_STATUS(AE_AML_NO_OPERAND);
L
Linus Torvalds 已提交
318 319
	}

320
	if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
L
Linus Torvalds 已提交
321 322 323 324 325
		/*
		 * If the buffer_field arguments have not been previously evaluated,
		 * evaluate them now and save the results.
		 */
		if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
L
Len Brown 已提交
326 327 328
			status = acpi_ds_get_buffer_field_arguments(obj_desc);
			if (ACPI_FAILURE(status)) {
				return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
329 330
			}
		}
331 332
	} else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
		   (obj_desc->field.region_obj->region.space_id ==
333 334
		    ACPI_ADR_SPACE_SMBUS
		    || obj_desc->field.region_obj->region.space_id ==
335 336
		    ACPI_ADR_SPACE_GSBUS
		    || obj_desc->field.region_obj->region.space_id ==
337
		    ACPI_ADR_SPACE_IPMI)) {
L
Linus Torvalds 已提交
338
		/*
339
		 * This is an SMBus, GSBus or IPMI write. We will bypass the entire field
340 341 342 343 344
		 * mechanism and handoff the buffer directly to the handler. For
		 * these address spaces, the buffer is bi-directional; on a write,
		 * return data is returned in the same buffer.
		 *
		 * Source must be a buffer of sufficient size:
345
		 * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE.
L
Linus Torvalds 已提交
346
		 *
347
		 * Note: SMBus and GSBus protocol type is passed in upper 16-bits of Function
L
Linus Torvalds 已提交
348
		 */
349
		if (source_desc->common.type != ACPI_TYPE_BUFFER) {
B
Bob Moore 已提交
350
			ACPI_ERROR((AE_INFO,
351
				    "SMBus/IPMI/GenericSerialBus write requires Buffer, found type %s",
B
Bob Moore 已提交
352
				    acpi_ut_get_object_type_name(source_desc)));
R
Robert Moore 已提交
353

L
Len Brown 已提交
354
			return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
L
Linus Torvalds 已提交
355 356
		}

357 358 359 360 361
		if (obj_desc->field.region_obj->region.space_id ==
		    ACPI_ADR_SPACE_SMBUS) {
			length = ACPI_SMBUS_BUFFER_SIZE;
			function =
			    ACPI_WRITE | (obj_desc->field.attribute << 16);
362 363
		} else if (obj_desc->field.region_obj->region.space_id ==
			   ACPI_ADR_SPACE_GSBUS) {
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
			accessor_type = obj_desc->field.attribute;
			length = acpi_ex_get_serial_access_length(accessor_type,
								  obj_desc->
								  field.
								  access_length);

			/*
			 * Add additional 2 bytes for modeled generic_serial_bus data buffer:
			 * typedef struct {
			 *     BYTEStatus; // Byte 0 of the data buffer
			 *     BYTELength; // Byte 1 of the data buffer
			 *     BYTE[x-1]Data; // Bytes 2-x of the arbitrary length data buffer,
			 * }
			 */
			length += 2;
			function = ACPI_WRITE | (accessor_type << 16);
380 381 382 383 384 385 386
		} else {	/* IPMI */

			length = ACPI_IPMI_BUFFER_SIZE;
			function = ACPI_WRITE;
		}

		if (source_desc->buffer.length < length) {
B
Bob Moore 已提交
387
			ACPI_ERROR((AE_INFO,
388
				    "SMBus/IPMI/GenericSerialBus write requires Buffer of length %u, found length %u",
389
				    length, source_desc->buffer.length));
R
Robert Moore 已提交
390

L
Len Brown 已提交
391
			return_ACPI_STATUS(AE_AML_BUFFER_LIMIT);
L
Linus Torvalds 已提交
392 393
		}

394 395 396
		/* Create the bi-directional buffer */

		buffer_desc = acpi_ut_create_buffer_object(length);
L
Linus Torvalds 已提交
397
		if (!buffer_desc) {
L
Len Brown 已提交
398
			return_ACPI_STATUS(AE_NO_MEMORY);
L
Linus Torvalds 已提交
399 400 401
		}

		buffer = buffer_desc->buffer.pointer;
402
		ACPI_MEMCPY(buffer, source_desc->buffer.pointer, length);
L
Linus Torvalds 已提交
403 404 405

		/* Lock entire transaction if requested */

406
		acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
L
Linus Torvalds 已提交
407 408

		/*
R
Robert Moore 已提交
409 410
		 * Perform the write (returns status and perhaps data in the
		 * same buffer)
L
Linus Torvalds 已提交
411
		 */
L
Len Brown 已提交
412
		status = acpi_ex_access_region(obj_desc, 0,
413
					       (u64 *) buffer, function);
414
		acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
L
Linus Torvalds 已提交
415 416

		*result_desc = buffer_desc;
L
Len Brown 已提交
417
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
418 419
	}

R
Robert Moore 已提交
420 421
	/* Get a pointer to the data to be written */

422
	switch (source_desc->common.type) {
L
Linus Torvalds 已提交
423
	case ACPI_TYPE_INTEGER:
424

L
Linus Torvalds 已提交
425
		buffer = &source_desc->integer.value;
L
Len Brown 已提交
426
		length = sizeof(source_desc->integer.value);
L
Linus Torvalds 已提交
427 428 429
		break;

	case ACPI_TYPE_BUFFER:
430

L
Linus Torvalds 已提交
431 432 433 434 435
		buffer = source_desc->buffer.pointer;
		length = source_desc->buffer.length;
		break;

	case ACPI_TYPE_STRING:
436

L
Linus Torvalds 已提交
437 438 439 440 441
		buffer = source_desc->string.pointer;
		length = source_desc->string.length;
		break;

	default:
442

L
Len Brown 已提交
443
		return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
L
Linus Torvalds 已提交
444 445
	}

L
Len Brown 已提交
446
	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
B
Bob Moore 已提交
447
			  "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
L
Len Brown 已提交
448
			  source_desc,
449 450
			  acpi_ut_get_type_name(source_desc->common.type),
			  source_desc->common.type, buffer, length));
L
Len Brown 已提交
451 452

	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
B
Bob Moore 已提交
453
			  "FieldWrite [TO]:   Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
L
Len Brown 已提交
454
			  obj_desc,
455 456
			  acpi_ut_get_type_name(obj_desc->common.type),
			  obj_desc->common.type,
L
Len Brown 已提交
457 458 459
			  obj_desc->common_field.bit_length,
			  obj_desc->common_field.start_field_bit_offset,
			  obj_desc->common_field.base_byte_offset));
L
Linus Torvalds 已提交
460 461 462

	/* Lock entire transaction if requested */

463
	acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
L
Linus Torvalds 已提交
464 465 466

	/* Write to the field */

L
Len Brown 已提交
467
	status = acpi_ex_insert_into_field(obj_desc, buffer, length);
468
	acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
L
Linus Torvalds 已提交
469

L
Len Brown 已提交
470
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
471
}