0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <acpi/acpi.h>
0011 #include "accommon.h"
0012 #include "acdispat.h"
0013 #include "acinterp.h"
0014 #include "amlcode.h"
0015
0016 #define _COMPONENT ACPI_EXECUTER
0017 ACPI_MODULE_NAME("exfield")
0018
0019
0020
0021
0022
0023 #define ACPI_INVALID_PROTOCOL_ID 0x80
0024 #define ACPI_MAX_PROTOCOL_ID 0x0F
0025 static const u8 acpi_protocol_lengths[] = {
0026 ACPI_INVALID_PROTOCOL_ID,
0027 ACPI_INVALID_PROTOCOL_ID,
0028 0x00,
0029 ACPI_INVALID_PROTOCOL_ID,
0030 0x01,
0031 ACPI_INVALID_PROTOCOL_ID,
0032 0x01,
0033 ACPI_INVALID_PROTOCOL_ID,
0034 0x02,
0035 ACPI_INVALID_PROTOCOL_ID,
0036 0xFF,
0037 0xFF,
0038 0x02,
0039 0xFF,
0040 0xFF,
0041 0xFF
0042 };
0043
0044 #define PCC_MASTER_SUBSPACE 3
0045
0046
0047
0048
0049
0050
0051
0052 #define GENERIC_SUBSPACE_COMMAND(a) (4 == a || a == 5)
0053 #define MASTER_SUBSPACE_COMMAND(a) (12 <= a && a <= 15)
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071 acpi_status
0072 acpi_ex_get_protocol_buffer_length(u32 protocol_id, u32 *return_length)
0073 {
0074
0075 if ((protocol_id > ACPI_MAX_PROTOCOL_ID) ||
0076 (acpi_protocol_lengths[protocol_id] == ACPI_INVALID_PROTOCOL_ID)) {
0077 ACPI_ERROR((AE_INFO,
0078 "Invalid Field/AccessAs protocol ID: 0x%4.4X",
0079 protocol_id));
0080
0081 return (AE_AML_PROTOCOL);
0082 }
0083
0084 *return_length = acpi_protocol_lengths[protocol_id];
0085 return (AE_OK);
0086 }
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104 acpi_status
0105 acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
0106 union acpi_operand_object *obj_desc,
0107 union acpi_operand_object **ret_buffer_desc)
0108 {
0109 acpi_status status;
0110 union acpi_operand_object *buffer_desc;
0111 void *buffer;
0112 u32 buffer_length;
0113
0114 ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);
0115
0116
0117
0118 if (!obj_desc) {
0119 return_ACPI_STATUS(AE_AML_NO_OPERAND);
0120 }
0121 if (!ret_buffer_desc) {
0122 return_ACPI_STATUS(AE_BAD_PARAMETER);
0123 }
0124
0125 if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
0126
0127
0128
0129
0130 if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
0131 status = acpi_ds_get_buffer_field_arguments(obj_desc);
0132 if (ACPI_FAILURE(status)) {
0133 return_ACPI_STATUS(status);
0134 }
0135 }
0136 } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
0137 (obj_desc->field.region_obj->region.space_id ==
0138 ACPI_ADR_SPACE_SMBUS
0139 || obj_desc->field.region_obj->region.space_id ==
0140 ACPI_ADR_SPACE_GSBUS
0141 || obj_desc->field.region_obj->region.space_id ==
0142 ACPI_ADR_SPACE_IPMI
0143 || obj_desc->field.region_obj->region.space_id ==
0144 ACPI_ADR_SPACE_PLATFORM_RT)) {
0145
0146
0147
0148 status = acpi_ex_read_serial_bus(obj_desc, ret_buffer_desc);
0149 return_ACPI_STATUS(status);
0150 }
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165 buffer_length =
0166 (acpi_size)ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length);
0167
0168 if (buffer_length > acpi_gbl_integer_byte_width ||
0169 (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD &&
0170 obj_desc->buffer_field.is_create_field)) {
0171
0172
0173
0174 buffer_desc = acpi_ut_create_buffer_object(buffer_length);
0175 if (!buffer_desc) {
0176 return_ACPI_STATUS(AE_NO_MEMORY);
0177 }
0178 buffer = buffer_desc->buffer.pointer;
0179 } else {
0180
0181
0182 buffer_desc = acpi_ut_create_integer_object((u64) 0);
0183 if (!buffer_desc) {
0184 return_ACPI_STATUS(AE_NO_MEMORY);
0185 }
0186
0187 buffer_length = acpi_gbl_integer_byte_width;
0188 buffer = &buffer_desc->integer.value;
0189 }
0190
0191 if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
0192 (obj_desc->field.region_obj->region.space_id ==
0193 ACPI_ADR_SPACE_GPIO)) {
0194
0195
0196
0197 status = acpi_ex_read_gpio(obj_desc, buffer);
0198 goto exit;
0199 } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
0200 (obj_desc->field.region_obj->region.space_id ==
0201 ACPI_ADR_SPACE_PLATFORM_COMM)) {
0202
0203
0204
0205
0206 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0207 "PCC FieldRead bits %u\n",
0208 obj_desc->field.bit_length));
0209
0210 memcpy(buffer,
0211 obj_desc->field.region_obj->field.internal_pcc_buffer +
0212 obj_desc->field.base_byte_offset,
0213 (acpi_size)ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.
0214 bit_length));
0215
0216 *ret_buffer_desc = buffer_desc;
0217 return AE_OK;
0218 }
0219
0220 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0221 "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n",
0222 obj_desc, obj_desc->common.type, buffer,
0223 buffer_length));
0224 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0225 "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
0226 obj_desc->common_field.bit_length,
0227 obj_desc->common_field.start_field_bit_offset,
0228 obj_desc->common_field.base_byte_offset));
0229
0230
0231
0232 acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
0233
0234
0235
0236 status = acpi_ex_extract_from_field(obj_desc, buffer, buffer_length);
0237 acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
0238
0239 exit:
0240 if (ACPI_FAILURE(status)) {
0241 acpi_ut_remove_reference(buffer_desc);
0242 } else {
0243 *ret_buffer_desc = buffer_desc;
0244 }
0245
0246 return_ACPI_STATUS(status);
0247 }
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263 acpi_status
0264 acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
0265 union acpi_operand_object *obj_desc,
0266 union acpi_operand_object **result_desc)
0267 {
0268 acpi_status status;
0269 u32 buffer_length;
0270 u32 data_length;
0271 void *buffer;
0272
0273 ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc);
0274
0275
0276
0277 if (!source_desc || !obj_desc) {
0278 return_ACPI_STATUS(AE_AML_NO_OPERAND);
0279 }
0280
0281 if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
0282
0283
0284
0285
0286 if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
0287 status = acpi_ds_get_buffer_field_arguments(obj_desc);
0288 if (ACPI_FAILURE(status)) {
0289 return_ACPI_STATUS(status);
0290 }
0291 }
0292 } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
0293 (obj_desc->field.region_obj->region.space_id ==
0294 ACPI_ADR_SPACE_GPIO)) {
0295
0296
0297
0298 status = acpi_ex_write_gpio(source_desc, obj_desc, result_desc);
0299 return_ACPI_STATUS(status);
0300 } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
0301 (obj_desc->field.region_obj->region.space_id ==
0302 ACPI_ADR_SPACE_SMBUS
0303 || obj_desc->field.region_obj->region.space_id ==
0304 ACPI_ADR_SPACE_GSBUS
0305 || obj_desc->field.region_obj->region.space_id ==
0306 ACPI_ADR_SPACE_IPMI
0307 || obj_desc->field.region_obj->region.space_id ==
0308 ACPI_ADR_SPACE_PLATFORM_RT)) {
0309
0310
0311
0312 status =
0313 acpi_ex_write_serial_bus(source_desc, obj_desc,
0314 result_desc);
0315 return_ACPI_STATUS(status);
0316 } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
0317 (obj_desc->field.region_obj->region.space_id ==
0318 ACPI_ADR_SPACE_PLATFORM_COMM)) {
0319
0320
0321
0322
0323
0324
0325
0326 data_length =
0327 (acpi_size)ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.
0328 bit_length);
0329 memcpy(obj_desc->field.region_obj->field.internal_pcc_buffer +
0330 obj_desc->field.base_byte_offset,
0331 source_desc->buffer.pointer, data_length);
0332
0333 if (MASTER_SUBSPACE_COMMAND(obj_desc->field.base_byte_offset)) {
0334
0335
0336
0337 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0338 "PCC COMD field has been written. Invoking PCC handler now.\n"));
0339
0340 status =
0341 acpi_ex_access_region(obj_desc, 0,
0342 (u64 *)obj_desc->field.
0343 region_obj->field.
0344 internal_pcc_buffer,
0345 ACPI_WRITE);
0346 return_ACPI_STATUS(status);
0347 }
0348 return (AE_OK);
0349 }
0350
0351
0352
0353 switch (source_desc->common.type) {
0354 case ACPI_TYPE_INTEGER:
0355
0356 buffer = &source_desc->integer.value;
0357 buffer_length = sizeof(source_desc->integer.value);
0358 break;
0359
0360 case ACPI_TYPE_BUFFER:
0361
0362 buffer = source_desc->buffer.pointer;
0363 buffer_length = source_desc->buffer.length;
0364 break;
0365
0366 case ACPI_TYPE_STRING:
0367
0368 buffer = source_desc->string.pointer;
0369 buffer_length = source_desc->string.length;
0370 break;
0371
0372 default:
0373 return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
0374 }
0375
0376 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0377 "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
0378 source_desc,
0379 acpi_ut_get_type_name(source_desc->common.type),
0380 source_desc->common.type, buffer, buffer_length));
0381
0382 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0383 "FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
0384 obj_desc,
0385 acpi_ut_get_type_name(obj_desc->common.type),
0386 obj_desc->common.type,
0387 obj_desc->common_field.bit_length,
0388 obj_desc->common_field.start_field_bit_offset,
0389 obj_desc->common_field.base_byte_offset));
0390
0391
0392
0393 acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
0394
0395
0396
0397 status = acpi_ex_insert_into_field(obj_desc, buffer, buffer_length);
0398 acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
0399 return_ACPI_STATUS(status);
0400 }