aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBob Moore <Robert.Moore@intel.com>2014-09-22 22:35:47 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-09-24 16:53:46 -0400
commit75ec6e55f1384548311a13ce4fcb39c516053314 (patch)
tree0165f3ba0f3fe31a1d27d17e4fee1a379df83c40
parent0f33be009b89d2268e94194dc4fd01a7851b6d51 (diff)
ACPICA: Update to GPIO region handler interface.
Changes to correct several GPIO issues: 1) The update_rule in a GPIO field definition is now ignored; a read-modify-write operation is never performed for GPIO fields. (Internally, this means that the field assembly/disassembly code is completely bypassed for GPIO.) 2) The Address parameter passed to a GPIO region handler is now the bit offset of the field from a previous Connection() operator. Thus, it becomes a "Pin Number Index" into the Connection() resource descriptor. 3) The bit_width parameter passed to a GPIO region handler is now the exact bit width of the GPIO field. Thus, it can be interpreted as "number of pins". Overall, we can now say that the region handler interface to GPIO handlers is a raw "bit/pin" addressed interface, not a byte-addressed interface like the system_memory handler interface. Signed-off-by: Bob Moore <robert.moore@intel.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com> Cc: 3.15+ <stable@vger.kernel.org> # 3.15+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/acpica/aclocal.h1
-rw-r--r--drivers/acpi/acpica/acobject.h1
-rw-r--r--drivers/acpi/acpica/dsfield.c2
-rw-r--r--drivers/acpi/acpica/evregion.c47
-rw-r--r--drivers/acpi/acpica/exfield.c67
-rw-r--r--drivers/acpi/acpica/exprep.c2
6 files changed, 104 insertions, 16 deletions
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 1f9aba5fb81f..2747279fbe3c 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -254,6 +254,7 @@ struct acpi_create_field_info {
254 u32 field_bit_position; 254 u32 field_bit_position;
255 u32 field_bit_length; 255 u32 field_bit_length;
256 u16 resource_length; 256 u16 resource_length;
257 u16 pin_number_index;
257 u8 field_flags; 258 u8 field_flags;
258 u8 attribute; 259 u8 attribute;
259 u8 field_type; 260 u8 field_type;
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
index 22fb6449d3d6..8abb393dafab 100644
--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -264,6 +264,7 @@ struct acpi_object_region_field {
264 ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO u16 resource_length; 264 ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO u16 resource_length;
265 union acpi_operand_object *region_obj; /* Containing op_region object */ 265 union acpi_operand_object *region_obj; /* Containing op_region object */
266 u8 *resource_buffer; /* resource_template for serial regions/fields */ 266 u8 *resource_buffer; /* resource_template for serial regions/fields */
267 u16 pin_number_index; /* Index relative to previous Connection/Template */
267}; 268};
268 269
269struct acpi_object_bank_field { 270struct acpi_object_bank_field {
diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c
index 3661c8e90540..c57666196672 100644
--- a/drivers/acpi/acpica/dsfield.c
+++ b/drivers/acpi/acpica/dsfield.c
@@ -360,6 +360,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
360 */ 360 */
361 info->resource_buffer = NULL; 361 info->resource_buffer = NULL;
362 info->connection_node = NULL; 362 info->connection_node = NULL;
363 info->pin_number_index = 0;
363 364
364 /* 365 /*
365 * A Connection() is either an actual resource descriptor (buffer) 366 * A Connection() is either an actual resource descriptor (buffer)
@@ -437,6 +438,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
437 } 438 }
438 439
439 info->field_bit_position += info->field_bit_length; 440 info->field_bit_position += info->field_bit_length;
441 info->pin_number_index++; /* Index relative to previous Connection() */
440 break; 442 break;
441 443
442 default: 444 default:
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c
index 9957297d1580..8eb8575e8c16 100644
--- a/drivers/acpi/acpica/evregion.c
+++ b/drivers/acpi/acpica/evregion.c
@@ -142,6 +142,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
142 union acpi_operand_object *region_obj2; 142 union acpi_operand_object *region_obj2;
143 void *region_context = NULL; 143 void *region_context = NULL;
144 struct acpi_connection_info *context; 144 struct acpi_connection_info *context;
145 acpi_physical_address address;
145 146
146 ACPI_FUNCTION_TRACE(ev_address_space_dispatch); 147 ACPI_FUNCTION_TRACE(ev_address_space_dispatch);
147 148
@@ -231,25 +232,23 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
231 /* We have everything we need, we can invoke the address space handler */ 232 /* We have everything we need, we can invoke the address space handler */
232 233
233 handler = handler_desc->address_space.handler; 234 handler = handler_desc->address_space.handler;
234 235 address = (region_obj->region.address + region_offset);
235 ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
236 "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
237 &region_obj->region.handler->address_space, handler,
238 ACPI_FORMAT_NATIVE_UINT(region_obj->region.address +
239 region_offset),
240 acpi_ut_get_region_name(region_obj->region.
241 space_id)));
242 236
243 /* 237 /*
244 * Special handling for generic_serial_bus and general_purpose_io: 238 * Special handling for generic_serial_bus and general_purpose_io:
245 * There are three extra parameters that must be passed to the 239 * There are three extra parameters that must be passed to the
246 * handler via the context: 240 * handler via the context:
247 * 1) Connection buffer, a resource template from Connection() op. 241 * 1) Connection buffer, a resource template from Connection() op
248 * 2) Length of the above buffer. 242 * 2) Length of the above buffer
249 * 3) Actual access length from the access_as() op. 243 * 3) Actual access length from the access_as() op
244 *
245 * In addition, for general_purpose_io, the Address and bit_width fields
246 * are defined as follows:
247 * 1) Address is the pin number index of the field (bit offset from
248 * the previous Connection)
249 * 2) bit_width is the actual bit length of the field (number of pins)
250 */ 250 */
251 if (((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) || 251 if ((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) &&
252 (region_obj->region.space_id == ACPI_ADR_SPACE_GPIO)) &&
253 context && field_obj) { 252 context && field_obj) {
254 253
255 /* Get the Connection (resource_template) buffer */ 254 /* Get the Connection (resource_template) buffer */
@@ -258,6 +257,24 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
258 context->length = field_obj->field.resource_length; 257 context->length = field_obj->field.resource_length;
259 context->access_length = field_obj->field.access_length; 258 context->access_length = field_obj->field.access_length;
260 } 259 }
260 if ((region_obj->region.space_id == ACPI_ADR_SPACE_GPIO) &&
261 context && field_obj) {
262
263 /* Get the Connection (resource_template) buffer */
264
265 context->connection = field_obj->field.resource_buffer;
266 context->length = field_obj->field.resource_length;
267 context->access_length = field_obj->field.access_length;
268 address = field_obj->field.pin_number_index;
269 bit_width = field_obj->field.bit_length;
270 }
271
272 ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
273 "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
274 &region_obj->region.handler->address_space, handler,
275 ACPI_FORMAT_NATIVE_UINT(address),
276 acpi_ut_get_region_name(region_obj->region.
277 space_id)));
261 278
262 if (!(handler_desc->address_space.handler_flags & 279 if (!(handler_desc->address_space.handler_flags &
263 ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { 280 ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
@@ -271,9 +288,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
271 288
272 /* Call the handler */ 289 /* Call the handler */
273 290
274 status = handler(function, 291 status = handler(function, address, bit_width, value, context,
275 (region_obj->region.address + region_offset),
276 bit_width, value, context,
277 region_obj2->extra.region_context); 292 region_obj2->extra.region_context);
278 293
279 if (ACPI_FAILURE(status)) { 294 if (ACPI_FAILURE(status)) {
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c
index 6907ce0c704c..b994845ed359 100644
--- a/drivers/acpi/acpica/exfield.c
+++ b/drivers/acpi/acpica/exfield.c
@@ -253,6 +253,37 @@ acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state,
253 buffer = &buffer_desc->integer.value; 253 buffer = &buffer_desc->integer.value;
254 } 254 }
255 255
256 if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
257 (obj_desc->field.region_obj->region.space_id ==
258 ACPI_ADR_SPACE_GPIO)) {
259 /*
260 * For GPIO (general_purpose_io), the Address will be the bit offset
261 * from the previous Connection() operator, making it effectively a
262 * pin number index. The bit_length is the length of the field, which
263 * is thus the number of pins.
264 */
265 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
266 "GPIO FieldRead [FROM]: Pin %u Bits %u\n",
267 obj_desc->field.pin_number_index,
268 obj_desc->field.bit_length));
269
270 /* Lock entire transaction if requested */
271
272 acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
273
274 /* Perform the write */
275
276 status = acpi_ex_access_region(obj_desc, 0,
277 (u64 *)buffer, ACPI_READ);
278 acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
279 if (ACPI_FAILURE(status)) {
280 acpi_ut_remove_reference(buffer_desc);
281 } else {
282 *ret_buffer_desc = buffer_desc;
283 }
284 return_ACPI_STATUS(status);
285 }
286
256 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, 287 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
257 "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", 288 "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n",
258 obj_desc, obj_desc->common.type, buffer, 289 obj_desc, obj_desc->common.type, buffer,
@@ -413,6 +444,42 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
413 444
414 *result_desc = buffer_desc; 445 *result_desc = buffer_desc;
415 return_ACPI_STATUS(status); 446 return_ACPI_STATUS(status);
447 } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
448 (obj_desc->field.region_obj->region.space_id ==
449 ACPI_ADR_SPACE_GPIO)) {
450 /*
451 * For GPIO (general_purpose_io), we will bypass the entire field
452 * mechanism and handoff the bit address and bit width directly to
453 * the handler. The Address will be the bit offset
454 * from the previous Connection() operator, making it effectively a
455 * pin number index. The bit_length is the length of the field, which
456 * is thus the number of pins.
457 */
458 if (source_desc->common.type != ACPI_TYPE_INTEGER) {
459 return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
460 }
461
462 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
463 "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n",
464 acpi_ut_get_type_name(source_desc->common.
465 type),
466 source_desc->common.type,
467 (u32)source_desc->integer.value,
468 obj_desc->field.pin_number_index,
469 obj_desc->field.bit_length));
470
471 buffer = &source_desc->integer.value;
472
473 /* Lock entire transaction if requested */
474
475 acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
476
477 /* Perform the write */
478
479 status = acpi_ex_access_region(obj_desc, 0,
480 (u64 *)buffer, ACPI_WRITE);
481 acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
482 return_ACPI_STATUS(status);
416 } 483 }
417 484
418 /* Get a pointer to the data to be written */ 485 /* Get a pointer to the data to be written */
diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c
index ee3f872870bc..118e942005e5 100644
--- a/drivers/acpi/acpica/exprep.c
+++ b/drivers/acpi/acpica/exprep.c
@@ -484,6 +484,8 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
484 obj_desc->field.resource_length = info->resource_length; 484 obj_desc->field.resource_length = info->resource_length;
485 } 485 }
486 486
487 obj_desc->field.pin_number_index = info->pin_number_index;
488
487 /* Allow full data read from EC address space */ 489 /* Allow full data read from EC address space */
488 490
489 if ((obj_desc->field.region_obj->region.space_id == 491 if ((obj_desc->field.region_obj->region.space_id ==