0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <acpi/acpi.h>
0011 #include "accommon.h"
0012 #include "acinterp.h"
0013 #include "amlcode.h"
0014 #include "acnamesp.h"
0015 #include "acdispat.h"
0016
0017 #define _COMPONENT ACPI_EXECUTER
0018 ACPI_MODULE_NAME("exprep")
0019
0020
0021 static u32
0022 acpi_ex_decode_field_access(union acpi_operand_object *obj_desc,
0023 u8 field_flags, u32 * return_byte_alignment);
0024
0025 #ifdef ACPI_UNDER_DEVELOPMENT
0026
0027 static u32
0028 acpi_ex_generate_access(u32 field_bit_offset,
0029 u32 field_bit_length, u32 region_length);
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053 static u32
0054 acpi_ex_generate_access(u32 field_bit_offset,
0055 u32 field_bit_length, u32 region_length)
0056 {
0057 u32 field_byte_length;
0058 u32 field_byte_offset;
0059 u32 field_byte_end_offset;
0060 u32 access_byte_width;
0061 u32 field_start_offset;
0062 u32 field_end_offset;
0063 u32 minimum_access_width = 0xFFFFFFFF;
0064 u32 minimum_accesses = 0xFFFFFFFF;
0065 u32 accesses;
0066
0067 ACPI_FUNCTION_TRACE(ex_generate_access);
0068
0069
0070
0071 field_byte_offset = ACPI_DIV_8(ACPI_ROUND_DOWN(field_bit_offset, 8));
0072
0073 field_byte_end_offset =
0074 ACPI_DIV_8(ACPI_ROUND_UP(field_bit_length + field_bit_offset, 8));
0075
0076 field_byte_length = field_byte_end_offset - field_byte_offset;
0077
0078 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0079 "Bit length %u, Bit offset %u\n",
0080 field_bit_length, field_bit_offset));
0081
0082 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0083 "Byte Length %u, Byte Offset %u, End Offset %u\n",
0084 field_byte_length, field_byte_offset,
0085 field_byte_end_offset));
0086
0087
0088
0089
0090
0091
0092
0093 for (access_byte_width = 1; access_byte_width <= 8;
0094 access_byte_width <<= 1) {
0095
0096
0097
0098
0099
0100
0101
0102 if (ACPI_ROUND_UP(field_byte_end_offset, access_byte_width) <=
0103 region_length) {
0104 field_start_offset =
0105 ACPI_ROUND_DOWN(field_byte_offset,
0106 access_byte_width) /
0107 access_byte_width;
0108
0109 field_end_offset =
0110 ACPI_ROUND_UP((field_byte_length +
0111 field_byte_offset),
0112 access_byte_width) /
0113 access_byte_width;
0114
0115 accesses = field_end_offset - field_start_offset;
0116
0117 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0118 "AccessWidth %u end is within region\n",
0119 access_byte_width));
0120
0121 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0122 "Field Start %u, Field End %u -- requires %u accesses\n",
0123 field_start_offset, field_end_offset,
0124 accesses));
0125
0126
0127
0128 if (accesses <= 1) {
0129 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0130 "Entire field can be accessed "
0131 "with one operation of size %u\n",
0132 access_byte_width));
0133 return_VALUE(access_byte_width);
0134 }
0135
0136
0137
0138
0139
0140 if (accesses < minimum_accesses) {
0141 minimum_accesses = accesses;
0142 minimum_access_width = access_byte_width;
0143 }
0144 } else {
0145 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0146 "AccessWidth %u end is NOT within region\n",
0147 access_byte_width));
0148 if (access_byte_width == 1) {
0149 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0150 "Field goes beyond end-of-region!\n"));
0151
0152
0153
0154 return_VALUE(0);
0155 }
0156
0157
0158
0159
0160
0161 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0162 "Backing off to previous optimal access width of %u\n",
0163 minimum_access_width));
0164 return_VALUE(minimum_access_width);
0165 }
0166 }
0167
0168
0169
0170
0171
0172 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0173 "Cannot access field in one operation, using width 8\n"));
0174
0175 return_VALUE(8);
0176 }
0177 #endif
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194 static u32
0195 acpi_ex_decode_field_access(union acpi_operand_object *obj_desc,
0196 u8 field_flags, u32 * return_byte_alignment)
0197 {
0198 u32 access;
0199 u32 byte_alignment;
0200 u32 bit_length;
0201
0202 ACPI_FUNCTION_TRACE(ex_decode_field_access);
0203
0204 access = (field_flags & AML_FIELD_ACCESS_TYPE_MASK);
0205
0206 switch (access) {
0207 case AML_FIELD_ACCESS_ANY:
0208
0209 #ifdef ACPI_UNDER_DEVELOPMENT
0210 byte_alignment =
0211 acpi_ex_generate_access(obj_desc->common_field.
0212 start_field_bit_offset,
0213 obj_desc->common_field.bit_length,
0214 0xFFFFFFFF
0215
0216 );
0217 bit_length = byte_alignment * 8;
0218 #endif
0219
0220 byte_alignment = 1;
0221 bit_length = 8;
0222 break;
0223
0224 case AML_FIELD_ACCESS_BYTE:
0225 case AML_FIELD_ACCESS_BUFFER:
0226
0227 byte_alignment = 1;
0228 bit_length = 8;
0229 break;
0230
0231 case AML_FIELD_ACCESS_WORD:
0232
0233 byte_alignment = 2;
0234 bit_length = 16;
0235 break;
0236
0237 case AML_FIELD_ACCESS_DWORD:
0238
0239 byte_alignment = 4;
0240 bit_length = 32;
0241 break;
0242
0243 case AML_FIELD_ACCESS_QWORD:
0244
0245 byte_alignment = 8;
0246 bit_length = 64;
0247 break;
0248
0249 default:
0250
0251
0252
0253 ACPI_ERROR((AE_INFO, "Unknown field access type 0x%X", access));
0254
0255 return_UINT32(0);
0256 }
0257
0258 if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
0259
0260
0261
0262
0263
0264 byte_alignment = 1;
0265 }
0266
0267 *return_byte_alignment = byte_alignment;
0268 return_UINT32(bit_length);
0269 }
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292 acpi_status
0293 acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc,
0294 u8 field_flags,
0295 u8 field_attribute,
0296 u32 field_bit_position, u32 field_bit_length)
0297 {
0298 u32 access_bit_width;
0299 u32 byte_alignment;
0300 u32 nearest_byte_address;
0301
0302 ACPI_FUNCTION_TRACE(ex_prep_common_field_object);
0303
0304
0305
0306
0307
0308
0309 obj_desc->common_field.field_flags = field_flags;
0310 obj_desc->common_field.attribute = field_attribute;
0311 obj_desc->common_field.bit_length = field_bit_length;
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328 access_bit_width =
0329 acpi_ex_decode_field_access(obj_desc, field_flags, &byte_alignment);
0330 if (!access_bit_width) {
0331 return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
0332 }
0333
0334
0335
0336 obj_desc->common_field.access_byte_width = (u8)
0337 ACPI_DIV_8(access_bit_width);
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349 nearest_byte_address =
0350 ACPI_ROUND_BITS_DOWN_TO_BYTES(field_bit_position);
0351 obj_desc->common_field.base_byte_offset = (u32)
0352 ACPI_ROUND_DOWN(nearest_byte_address, byte_alignment);
0353
0354
0355
0356
0357
0358 obj_desc->common_field.start_field_bit_offset = (u8)
0359 (field_bit_position -
0360 ACPI_MUL_8(obj_desc->common_field.base_byte_offset));
0361
0362 return_ACPI_STATUS(AE_OK);
0363 }
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378 acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
0379 {
0380 union acpi_operand_object *obj_desc;
0381 union acpi_operand_object *second_desc = NULL;
0382 acpi_status status;
0383 u32 access_byte_width;
0384 u32 type;
0385
0386 ACPI_FUNCTION_TRACE(ex_prep_field_value);
0387
0388
0389
0390 if (info->field_type != ACPI_TYPE_LOCAL_INDEX_FIELD) {
0391 if (!info->region_node) {
0392 ACPI_ERROR((AE_INFO, "Null RegionNode"));
0393 return_ACPI_STATUS(AE_AML_NO_OPERAND);
0394 }
0395
0396 type = acpi_ns_get_type(info->region_node);
0397 if (type != ACPI_TYPE_REGION) {
0398 ACPI_ERROR((AE_INFO,
0399 "Needed Region, found type 0x%X (%s)", type,
0400 acpi_ut_get_type_name(type)));
0401
0402 return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
0403 }
0404 }
0405
0406
0407
0408 obj_desc = acpi_ut_create_internal_object(info->field_type);
0409 if (!obj_desc) {
0410 return_ACPI_STATUS(AE_NO_MEMORY);
0411 }
0412
0413
0414
0415 obj_desc->common_field.node = info->field_node;
0416 status = acpi_ex_prep_common_field_object(obj_desc,
0417 info->field_flags,
0418 info->attribute,
0419 info->field_bit_position,
0420 info->field_bit_length);
0421 if (ACPI_FAILURE(status)) {
0422 acpi_ut_delete_object_desc(obj_desc);
0423 return_ACPI_STATUS(status);
0424 }
0425
0426
0427
0428 switch (info->field_type) {
0429 case ACPI_TYPE_LOCAL_REGION_FIELD:
0430
0431 obj_desc->field.region_obj =
0432 acpi_ns_get_attached_object(info->region_node);
0433
0434
0435
0436 obj_desc->field.access_length = info->access_length;
0437
0438 if (info->connection_node) {
0439 second_desc = info->connection_node->object;
0440 if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) {
0441 status =
0442 acpi_ds_get_buffer_arguments(second_desc);
0443 if (ACPI_FAILURE(status)) {
0444 acpi_ut_delete_object_desc(obj_desc);
0445 return_ACPI_STATUS(status);
0446 }
0447 }
0448
0449 obj_desc->field.resource_buffer =
0450 second_desc->buffer.pointer;
0451 obj_desc->field.resource_length =
0452 (u16)second_desc->buffer.length;
0453 } else if (info->resource_buffer) {
0454 obj_desc->field.resource_buffer = info->resource_buffer;
0455 obj_desc->field.resource_length = info->resource_length;
0456 }
0457
0458 obj_desc->field.pin_number_index = info->pin_number_index;
0459
0460
0461
0462 if ((obj_desc->field.region_obj->region.space_id ==
0463 ACPI_ADR_SPACE_EC)
0464 && (obj_desc->common_field.bit_length > 8)) {
0465 access_byte_width =
0466 ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.
0467 bit_length);
0468
0469
0470
0471 if (access_byte_width < 256) {
0472 obj_desc->common_field.access_byte_width =
0473 (u8)access_byte_width;
0474 }
0475 }
0476 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0477 "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n",
0478 obj_desc->field.start_field_bit_offset,
0479 obj_desc->field.base_byte_offset,
0480 obj_desc->field.access_byte_width,
0481 obj_desc->field.region_obj));
0482 break;
0483
0484 case ACPI_TYPE_LOCAL_BANK_FIELD:
0485
0486 obj_desc->bank_field.value = info->bank_value;
0487 obj_desc->bank_field.region_obj =
0488 acpi_ns_get_attached_object(info->region_node);
0489 obj_desc->bank_field.bank_obj =
0490 acpi_ns_get_attached_object(info->register_node);
0491
0492
0493
0494 acpi_ut_add_reference(obj_desc->bank_field.region_obj);
0495 acpi_ut_add_reference(obj_desc->bank_field.bank_obj);
0496
0497 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0498 "Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n",
0499 obj_desc->bank_field.start_field_bit_offset,
0500 obj_desc->bank_field.base_byte_offset,
0501 obj_desc->field.access_byte_width,
0502 obj_desc->bank_field.region_obj,
0503 obj_desc->bank_field.bank_obj));
0504
0505
0506
0507
0508
0509
0510 second_desc = obj_desc->common.next_object;
0511 second_desc->extra.aml_start =
0512 ACPI_CAST_PTR(union acpi_parse_object,
0513 info->data_register_node)->named.data;
0514 second_desc->extra.aml_length =
0515 ACPI_CAST_PTR(union acpi_parse_object,
0516 info->data_register_node)->named.length;
0517
0518 break;
0519
0520 case ACPI_TYPE_LOCAL_INDEX_FIELD:
0521
0522
0523
0524 obj_desc->index_field.index_obj =
0525 acpi_ns_get_attached_object(info->register_node);
0526 obj_desc->index_field.data_obj =
0527 acpi_ns_get_attached_object(info->data_register_node);
0528
0529 if (!obj_desc->index_field.data_obj
0530 || !obj_desc->index_field.index_obj) {
0531 ACPI_ERROR((AE_INFO,
0532 "Null Index Object during field prep"));
0533 acpi_ut_delete_object_desc(obj_desc);
0534 return_ACPI_STATUS(AE_AML_INTERNAL);
0535 }
0536
0537
0538
0539 acpi_ut_add_reference(obj_desc->index_field.data_obj);
0540 acpi_ut_add_reference(obj_desc->index_field.index_obj);
0541
0542
0543
0544
0545
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559 obj_desc->index_field.value =
0560 (u32) ACPI_ROUND_DOWN(ACPI_DIV_8(info->field_bit_position),
0561 obj_desc->index_field.
0562 access_byte_width);
0563
0564 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0565 "IndexField: BitOff %X, Off %X, Value %X, "
0566 "Gran %X, Index %p, Data %p\n",
0567 obj_desc->index_field.start_field_bit_offset,
0568 obj_desc->index_field.base_byte_offset,
0569 obj_desc->index_field.value,
0570 obj_desc->field.access_byte_width,
0571 obj_desc->index_field.index_obj,
0572 obj_desc->index_field.data_obj));
0573 break;
0574
0575 default:
0576
0577
0578
0579 break;
0580 }
0581
0582
0583
0584
0585
0586 status =
0587 acpi_ns_attach_object(info->field_node, obj_desc,
0588 acpi_ns_get_type(info->field_node));
0589
0590 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0591 "Set NamedObj %p [%4.4s], ObjDesc %p\n",
0592 info->field_node,
0593 acpi_ut_get_node_name(info->field_node), obj_desc));
0594
0595
0596
0597 acpi_ut_remove_reference(obj_desc);
0598 return_ACPI_STATUS(status);
0599 }