xref: /linux/drivers/acpi/acpica/exfield.c (revision cc1e6315e83db0e517dd9279050b88adc83a7eba)
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /******************************************************************************
3  *
4  * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
5  *
6  * Copyright (C) 2000 - 2018, Intel Corp.
7  *
8  *****************************************************************************/
9 
10 #include <acpi/acpi.h>
11 #include "accommon.h"
12 #include "acdispat.h"
13 #include "acinterp.h"
14 #include "amlcode.h"
15 
16 #define _COMPONENT          ACPI_EXECUTER
17 ACPI_MODULE_NAME("exfield")
18 
19 /* Local prototypes */
20 static u32
21 acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length);
22 
23 /*******************************************************************************
24  *
25  * FUNCTION:    acpi_ex_get_serial_access_length
26  *
27  * PARAMETERS:  accessor_type   - The type of the protocol indicated by region
28  *                                field access attributes
29  *              access_length   - The access length of the region field
30  *
31  * RETURN:      Decoded access length
32  *
33  * DESCRIPTION: This routine returns the length of the generic_serial_bus
34  *              protocol bytes
35  *
36  ******************************************************************************/
37 
38 static u32
39 acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length)
40 {
41 	u32 length;
42 
43 	switch (accessor_type) {
44 	case AML_FIELD_ATTRIB_QUICK:
45 
46 		length = 0;
47 		break;
48 
49 	case AML_FIELD_ATTRIB_SEND_RCV:
50 	case AML_FIELD_ATTRIB_BYTE:
51 
52 		length = 1;
53 		break;
54 
55 	case AML_FIELD_ATTRIB_WORD:
56 	case AML_FIELD_ATTRIB_WORD_CALL:
57 
58 		length = 2;
59 		break;
60 
61 	case AML_FIELD_ATTRIB_MULTIBYTE:
62 	case AML_FIELD_ATTRIB_RAW_BYTES:
63 	case AML_FIELD_ATTRIB_RAW_PROCESS:
64 
65 		length = access_length;
66 		break;
67 
68 	case AML_FIELD_ATTRIB_BLOCK:
69 	case AML_FIELD_ATTRIB_BLOCK_CALL:
70 	default:
71 
72 		length = ACPI_GSBUS_BUFFER_SIZE - 2;
73 		break;
74 	}
75 
76 	return (length);
77 }
78 
79 /*******************************************************************************
80  *
81  * FUNCTION:    acpi_ex_read_data_from_field
82  *
83  * PARAMETERS:  walk_state          - Current execution state
84  *              obj_desc            - The named field
85  *              ret_buffer_desc     - Where the return data object is stored
86  *
87  * RETURN:      Status
88  *
89  * DESCRIPTION: Read from a named field. Returns either an Integer or a
90  *              Buffer, depending on the size of the field.
91  *
92  ******************************************************************************/
93 
94 acpi_status
95 acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
96 			     union acpi_operand_object *obj_desc,
97 			     union acpi_operand_object **ret_buffer_desc)
98 {
99 	acpi_status status;
100 	union acpi_operand_object *buffer_desc;
101 	acpi_size length;
102 	void *buffer;
103 	u32 function;
104 	u16 accessor_type;
105 
106 	ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);
107 
108 	/* Parameter validation */
109 
110 	if (!obj_desc) {
111 		return_ACPI_STATUS(AE_AML_NO_OPERAND);
112 	}
113 	if (!ret_buffer_desc) {
114 		return_ACPI_STATUS(AE_BAD_PARAMETER);
115 	}
116 
117 	if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
118 		/*
119 		 * If the buffer_field arguments have not been previously evaluated,
120 		 * evaluate them now and save the results.
121 		 */
122 		if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
123 			status = acpi_ds_get_buffer_field_arguments(obj_desc);
124 			if (ACPI_FAILURE(status)) {
125 				return_ACPI_STATUS(status);
126 			}
127 		}
128 	} else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
129 		   (obj_desc->field.region_obj->region.space_id ==
130 		    ACPI_ADR_SPACE_SMBUS
131 		    || obj_desc->field.region_obj->region.space_id ==
132 		    ACPI_ADR_SPACE_GSBUS
133 		    || obj_desc->field.region_obj->region.space_id ==
134 		    ACPI_ADR_SPACE_IPMI)) {
135 		/*
136 		 * This is an SMBus, GSBus or IPMI read. We must create a buffer to
137 		 * hold the data and then directly access the region handler.
138 		 *
139 		 * Note: SMBus and GSBus protocol value is passed in upper 16-bits
140 		 * of Function
141 		 */
142 		if (obj_desc->field.region_obj->region.space_id ==
143 		    ACPI_ADR_SPACE_SMBUS) {
144 			length = ACPI_SMBUS_BUFFER_SIZE;
145 			function =
146 			    ACPI_READ | (obj_desc->field.attribute << 16);
147 		} else if (obj_desc->field.region_obj->region.space_id ==
148 			   ACPI_ADR_SPACE_GSBUS) {
149 			accessor_type = obj_desc->field.attribute;
150 			length =
151 			    acpi_ex_get_serial_access_length(accessor_type,
152 							     obj_desc->field.
153 							     access_length);
154 
155 			/*
156 			 * Add additional 2 bytes for the generic_serial_bus data buffer:
157 			 *
158 			 *     Status;    (Byte 0 of the data buffer)
159 			 *     Length;    (Byte 1 of the data buffer)
160 			 *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
161 			 */
162 			length += 2;
163 			function = ACPI_READ | (accessor_type << 16);
164 		} else {	/* IPMI */
165 
166 			length = ACPI_IPMI_BUFFER_SIZE;
167 			function = ACPI_READ;
168 		}
169 
170 		buffer_desc = acpi_ut_create_buffer_object(length);
171 		if (!buffer_desc) {
172 			return_ACPI_STATUS(AE_NO_MEMORY);
173 		}
174 
175 		/* Lock entire transaction if requested */
176 
177 		acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
178 
179 		/* Call the region handler for the read */
180 
181 		status = acpi_ex_access_region(obj_desc, 0,
182 					       ACPI_CAST_PTR(u64,
183 							     buffer_desc->
184 							     buffer.pointer),
185 					       function);
186 
187 		acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
188 		goto exit;
189 	}
190 
191 	/*
192 	 * Allocate a buffer for the contents of the field.
193 	 *
194 	 * If the field is larger than the current integer width, create
195 	 * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
196 	 * the use of arithmetic operators on the returned value if the
197 	 * field size is equal or smaller than an Integer.
198 	 *
199 	 * Note: Field.length is in bits.
200 	 */
201 	length =
202 	    (acpi_size)ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length);
203 
204 	if (length > acpi_gbl_integer_byte_width) {
205 
206 		/* Field is too large for an Integer, create a Buffer instead */
207 
208 		buffer_desc = acpi_ut_create_buffer_object(length);
209 		if (!buffer_desc) {
210 			return_ACPI_STATUS(AE_NO_MEMORY);
211 		}
212 		buffer = buffer_desc->buffer.pointer;
213 	} else {
214 		/* Field will fit within an Integer (normal case) */
215 
216 		buffer_desc = acpi_ut_create_integer_object((u64) 0);
217 		if (!buffer_desc) {
218 			return_ACPI_STATUS(AE_NO_MEMORY);
219 		}
220 
221 		length = acpi_gbl_integer_byte_width;
222 		buffer = &buffer_desc->integer.value;
223 	}
224 
225 	if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
226 	    (obj_desc->field.region_obj->region.space_id ==
227 	     ACPI_ADR_SPACE_GPIO)) {
228 		/*
229 		 * For GPIO (general_purpose_io), the Address will be the bit offset
230 		 * from the previous Connection() operator, making it effectively a
231 		 * pin number index. The bit_length is the length of the field, which
232 		 * is thus the number of pins.
233 		 */
234 		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
235 				  "GPIO FieldRead [FROM]:  Pin %u Bits %u\n",
236 				  obj_desc->field.pin_number_index,
237 				  obj_desc->field.bit_length));
238 
239 		/* Lock entire transaction if requested */
240 
241 		acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
242 
243 		/* Perform the write */
244 
245 		status =
246 		    acpi_ex_access_region(obj_desc, 0, (u64 *)buffer,
247 					  ACPI_READ);
248 
249 		acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
250 		if (ACPI_FAILURE(status)) {
251 			acpi_ut_remove_reference(buffer_desc);
252 		} else {
253 			*ret_buffer_desc = buffer_desc;
254 		}
255 		return_ACPI_STATUS(status);
256 	}
257 
258 	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
259 			  "FieldRead [TO]:   Obj %p, Type %X, Buf %p, ByteLen %X\n",
260 			  obj_desc, obj_desc->common.type, buffer,
261 			  (u32) length));
262 	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
263 			  "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
264 			  obj_desc->common_field.bit_length,
265 			  obj_desc->common_field.start_field_bit_offset,
266 			  obj_desc->common_field.base_byte_offset));
267 
268 	/* Lock entire transaction if requested */
269 
270 	acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
271 
272 	/* Read from the field */
273 
274 	status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length);
275 	acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
276 
277 exit:
278 	if (ACPI_FAILURE(status)) {
279 		acpi_ut_remove_reference(buffer_desc);
280 	} else {
281 		*ret_buffer_desc = buffer_desc;
282 	}
283 
284 	return_ACPI_STATUS(status);
285 }
286 
287 /*******************************************************************************
288  *
289  * FUNCTION:    acpi_ex_write_data_to_field
290  *
291  * PARAMETERS:  source_desc         - Contains data to write
292  *              obj_desc            - The named field
293  *              result_desc         - Where the return value is returned, if any
294  *
295  * RETURN:      Status
296  *
297  * DESCRIPTION: Write to a named field
298  *
299  ******************************************************************************/
300 
301 acpi_status
302 acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
303 			    union acpi_operand_object *obj_desc,
304 			    union acpi_operand_object **result_desc)
305 {
306 	acpi_status status;
307 	u32 length;
308 	void *buffer;
309 	union acpi_operand_object *buffer_desc;
310 	u32 function;
311 	u16 accessor_type;
312 
313 	ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc);
314 
315 	/* Parameter validation */
316 
317 	if (!source_desc || !obj_desc) {
318 		return_ACPI_STATUS(AE_AML_NO_OPERAND);
319 	}
320 
321 	if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
322 		/*
323 		 * If the buffer_field arguments have not been previously evaluated,
324 		 * evaluate them now and save the results.
325 		 */
326 		if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
327 			status = acpi_ds_get_buffer_field_arguments(obj_desc);
328 			if (ACPI_FAILURE(status)) {
329 				return_ACPI_STATUS(status);
330 			}
331 		}
332 	} else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
333 		   (obj_desc->field.region_obj->region.space_id ==
334 		    ACPI_ADR_SPACE_SMBUS
335 		    || obj_desc->field.region_obj->region.space_id ==
336 		    ACPI_ADR_SPACE_GSBUS
337 		    || obj_desc->field.region_obj->region.space_id ==
338 		    ACPI_ADR_SPACE_IPMI)) {
339 		/*
340 		 * This is an SMBus, GSBus or IPMI write. We will bypass the entire
341 		 * field mechanism and handoff the buffer directly to the handler.
342 		 * For these address spaces, the buffer is bi-directional; on a
343 		 * write, return data is returned in the same buffer.
344 		 *
345 		 * Source must be a buffer of sufficient size:
346 		 * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or
347 		 * ACPI_IPMI_BUFFER_SIZE.
348 		 *
349 		 * Note: SMBus and GSBus protocol type is passed in upper 16-bits
350 		 * of Function
351 		 */
352 		if (source_desc->common.type != ACPI_TYPE_BUFFER) {
353 			ACPI_ERROR((AE_INFO,
354 				    "SMBus/IPMI/GenericSerialBus write requires "
355 				    "Buffer, found type %s",
356 				    acpi_ut_get_object_type_name(source_desc)));
357 
358 			return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
359 		}
360 
361 		if (obj_desc->field.region_obj->region.space_id ==
362 		    ACPI_ADR_SPACE_SMBUS) {
363 			length = ACPI_SMBUS_BUFFER_SIZE;
364 			function =
365 			    ACPI_WRITE | (obj_desc->field.attribute << 16);
366 		} else if (obj_desc->field.region_obj->region.space_id ==
367 			   ACPI_ADR_SPACE_GSBUS) {
368 			accessor_type = obj_desc->field.attribute;
369 			length =
370 			    acpi_ex_get_serial_access_length(accessor_type,
371 							     obj_desc->field.
372 							     access_length);
373 
374 			/*
375 			 * Add additional 2 bytes for the generic_serial_bus data buffer:
376 			 *
377 			 *     Status;    (Byte 0 of the data buffer)
378 			 *     Length;    (Byte 1 of the data buffer)
379 			 *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
380 			 */
381 			length += 2;
382 			function = ACPI_WRITE | (accessor_type << 16);
383 		} else {	/* IPMI */
384 
385 			length = ACPI_IPMI_BUFFER_SIZE;
386 			function = ACPI_WRITE;
387 		}
388 
389 		if (source_desc->buffer.length < length) {
390 			ACPI_ERROR((AE_INFO,
391 				    "SMBus/IPMI/GenericSerialBus write requires "
392 				    "Buffer of length %u, found length %u",
393 				    length, source_desc->buffer.length));
394 
395 			return_ACPI_STATUS(AE_AML_BUFFER_LIMIT);
396 		}
397 
398 		/* Create the bi-directional buffer */
399 
400 		buffer_desc = acpi_ut_create_buffer_object(length);
401 		if (!buffer_desc) {
402 			return_ACPI_STATUS(AE_NO_MEMORY);
403 		}
404 
405 		buffer = buffer_desc->buffer.pointer;
406 		memcpy(buffer, source_desc->buffer.pointer, length);
407 
408 		/* Lock entire transaction if requested */
409 
410 		acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
411 
412 		/*
413 		 * Perform the write (returns status and perhaps data in the
414 		 * same buffer)
415 		 */
416 		status =
417 		    acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, function);
418 		acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
419 
420 		*result_desc = buffer_desc;
421 		return_ACPI_STATUS(status);
422 	} else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
423 		   (obj_desc->field.region_obj->region.space_id ==
424 		    ACPI_ADR_SPACE_GPIO)) {
425 		/*
426 		 * For GPIO (general_purpose_io), we will bypass the entire field
427 		 * mechanism and handoff the bit address and bit width directly to
428 		 * the handler. The Address will be the bit offset
429 		 * from the previous Connection() operator, making it effectively a
430 		 * pin number index. The bit_length is the length of the field, which
431 		 * is thus the number of pins.
432 		 */
433 		if (source_desc->common.type != ACPI_TYPE_INTEGER) {
434 			return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
435 		}
436 
437 		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
438 				  "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X  [TO]: Pin %u Bits %u\n",
439 				  acpi_ut_get_type_name(source_desc->common.
440 							type),
441 				  source_desc->common.type,
442 				  (u32)source_desc->integer.value,
443 				  obj_desc->field.pin_number_index,
444 				  obj_desc->field.bit_length));
445 
446 		buffer = &source_desc->integer.value;
447 
448 		/* Lock entire transaction if requested */
449 
450 		acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
451 
452 		/* Perform the write */
453 
454 		status =
455 		    acpi_ex_access_region(obj_desc, 0, (u64 *)buffer,
456 					  ACPI_WRITE);
457 		acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
458 		return_ACPI_STATUS(status);
459 	}
460 
461 	/* Get a pointer to the data to be written */
462 
463 	switch (source_desc->common.type) {
464 	case ACPI_TYPE_INTEGER:
465 
466 		buffer = &source_desc->integer.value;
467 		length = sizeof(source_desc->integer.value);
468 		break;
469 
470 	case ACPI_TYPE_BUFFER:
471 
472 		buffer = source_desc->buffer.pointer;
473 		length = source_desc->buffer.length;
474 		break;
475 
476 	case ACPI_TYPE_STRING:
477 
478 		buffer = source_desc->string.pointer;
479 		length = source_desc->string.length;
480 		break;
481 
482 	default:
483 
484 		return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
485 	}
486 
487 	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
488 			  "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
489 			  source_desc,
490 			  acpi_ut_get_type_name(source_desc->common.type),
491 			  source_desc->common.type, buffer, length));
492 
493 	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
494 			  "FieldWrite [TO]:   Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
495 			  obj_desc,
496 			  acpi_ut_get_type_name(obj_desc->common.type),
497 			  obj_desc->common.type,
498 			  obj_desc->common_field.bit_length,
499 			  obj_desc->common_field.start_field_bit_offset,
500 			  obj_desc->common_field.base_byte_offset));
501 
502 	/* Lock entire transaction if requested */
503 
504 	acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
505 
506 	/* Write to the field */
507 
508 	status = acpi_ex_insert_into_field(obj_desc, buffer, length);
509 	acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
510 
511 	return_ACPI_STATUS(status);
512 }
513