diff options
Diffstat (limited to 'drivers/acpi/acpica/exconfig.c')
-rw-r--r-- | drivers/acpi/acpica/exconfig.c | 125 |
1 files changed, 102 insertions, 23 deletions
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 3deb20a126b..277fd609611 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include "acnamesp.h" | 47 | #include "acnamesp.h" |
48 | #include "actables.h" | 48 | #include "actables.h" |
49 | #include "acdispat.h" | 49 | #include "acdispat.h" |
50 | #include "acevents.h" | ||
50 | 51 | ||
51 | #define _COMPONENT ACPI_EXECUTER | 52 | #define _COMPONENT ACPI_EXECUTER |
52 | ACPI_MODULE_NAME("exconfig") | 53 | ACPI_MODULE_NAME("exconfig") |
@@ -57,6 +58,10 @@ acpi_ex_add_table(u32 table_index, | |||
57 | struct acpi_namespace_node *parent_node, | 58 | struct acpi_namespace_node *parent_node, |
58 | union acpi_operand_object **ddb_handle); | 59 | union acpi_operand_object **ddb_handle); |
59 | 60 | ||
61 | static acpi_status | ||
62 | acpi_ex_region_read(union acpi_operand_object *obj_desc, | ||
63 | u32 length, u8 *buffer); | ||
64 | |||
60 | /******************************************************************************* | 65 | /******************************************************************************* |
61 | * | 66 | * |
62 | * FUNCTION: acpi_ex_add_table | 67 | * FUNCTION: acpi_ex_add_table |
@@ -91,6 +96,7 @@ acpi_ex_add_table(u32 table_index, | |||
91 | 96 | ||
92 | /* Init the table handle */ | 97 | /* Init the table handle */ |
93 | 98 | ||
99 | obj_desc->common.flags |= AOPOBJ_DATA_VALID; | ||
94 | obj_desc->reference.class = ACPI_REFCLASS_TABLE; | 100 | obj_desc->reference.class = ACPI_REFCLASS_TABLE; |
95 | *ddb_handle = obj_desc; | 101 | *ddb_handle = obj_desc; |
96 | 102 | ||
@@ -229,6 +235,8 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, | |||
229 | walk_state); | 235 | walk_state); |
230 | if (ACPI_FAILURE(status)) { | 236 | if (ACPI_FAILURE(status)) { |
231 | (void)acpi_ex_unload_table(ddb_handle); | 237 | (void)acpi_ex_unload_table(ddb_handle); |
238 | |||
239 | acpi_ut_remove_reference(ddb_handle); | ||
232 | return_ACPI_STATUS(status); | 240 | return_ACPI_STATUS(status); |
233 | } | 241 | } |
234 | } | 242 | } |
@@ -254,6 +262,47 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, | |||
254 | 262 | ||
255 | /******************************************************************************* | 263 | /******************************************************************************* |
256 | * | 264 | * |
265 | * FUNCTION: acpi_ex_region_read | ||
266 | * | ||
267 | * PARAMETERS: obj_desc - Region descriptor | ||
268 | * Length - Number of bytes to read | ||
269 | * Buffer - Pointer to where to put the data | ||
270 | * | ||
271 | * RETURN: Status | ||
272 | * | ||
273 | * DESCRIPTION: Read data from an operation region. The read starts from the | ||
274 | * beginning of the region. | ||
275 | * | ||
276 | ******************************************************************************/ | ||
277 | |||
278 | static acpi_status | ||
279 | acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer) | ||
280 | { | ||
281 | acpi_status status; | ||
282 | acpi_integer value; | ||
283 | u32 region_offset = 0; | ||
284 | u32 i; | ||
285 | |||
286 | /* Bytewise reads */ | ||
287 | |||
288 | for (i = 0; i < length; i++) { | ||
289 | status = acpi_ev_address_space_dispatch(obj_desc, ACPI_READ, | ||
290 | region_offset, 8, | ||
291 | &value); | ||
292 | if (ACPI_FAILURE(status)) { | ||
293 | return status; | ||
294 | } | ||
295 | |||
296 | *buffer = (u8)value; | ||
297 | buffer++; | ||
298 | region_offset++; | ||
299 | } | ||
300 | |||
301 | return AE_OK; | ||
302 | } | ||
303 | |||
304 | /******************************************************************************* | ||
305 | * | ||
257 | * FUNCTION: acpi_ex_load_op | 306 | * FUNCTION: acpi_ex_load_op |
258 | * | 307 | * |
259 | * PARAMETERS: obj_desc - Region or Buffer/Field where the table will be | 308 | * PARAMETERS: obj_desc - Region or Buffer/Field where the table will be |
@@ -314,18 +363,23 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, | |||
314 | } | 363 | } |
315 | } | 364 | } |
316 | 365 | ||
317 | /* | 366 | /* Get the table header first so we can get the table length */ |
318 | * Map the table header and get the actual table length. The region | 367 | |
319 | * length is not guaranteed to be the same as the table length. | 368 | table = ACPI_ALLOCATE(sizeof(struct acpi_table_header)); |
320 | */ | ||
321 | table = acpi_os_map_memory(obj_desc->region.address, | ||
322 | sizeof(struct acpi_table_header)); | ||
323 | if (!table) { | 369 | if (!table) { |
324 | return_ACPI_STATUS(AE_NO_MEMORY); | 370 | return_ACPI_STATUS(AE_NO_MEMORY); |
325 | } | 371 | } |
326 | 372 | ||
373 | status = | ||
374 | acpi_ex_region_read(obj_desc, | ||
375 | sizeof(struct acpi_table_header), | ||
376 | ACPI_CAST_PTR(u8, table)); | ||
327 | length = table->length; | 377 | length = table->length; |
328 | acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); | 378 | ACPI_FREE(table); |
379 | |||
380 | if (ACPI_FAILURE(status)) { | ||
381 | return_ACPI_STATUS(status); | ||
382 | } | ||
329 | 383 | ||
330 | /* Must have at least an ACPI table header */ | 384 | /* Must have at least an ACPI table header */ |
331 | 385 | ||
@@ -334,10 +388,19 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, | |||
334 | } | 388 | } |
335 | 389 | ||
336 | /* | 390 | /* |
337 | * The memory region is not guaranteed to remain stable and we must | 391 | * The original implementation simply mapped the table, with no copy. |
338 | * copy the table to a local buffer. For example, the memory region | 392 | * However, the memory region is not guaranteed to remain stable and |
339 | * is corrupted after suspend on some machines. Dynamically loaded | 393 | * we must copy the table to a local buffer. For example, the memory |
340 | * tables are usually small, so this overhead is minimal. | 394 | * region is corrupted after suspend on some machines. Dynamically |
395 | * loaded tables are usually small, so this overhead is minimal. | ||
396 | * | ||
397 | * The latest implementation (5/2009) does not use a mapping at all. | ||
398 | * We use the low-level operation region interface to read the table | ||
399 | * instead of the obvious optimization of using a direct mapping. | ||
400 | * This maintains a consistent use of operation regions across the | ||
401 | * entire subsystem. This is important if additional processing must | ||
402 | * be performed in the (possibly user-installed) operation region | ||
403 | * handler. For example, acpi_exec and ASLTS depend on this. | ||
341 | */ | 404 | */ |
342 | 405 | ||
343 | /* Allocate a buffer for the table */ | 406 | /* Allocate a buffer for the table */ |
@@ -347,17 +410,16 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, | |||
347 | return_ACPI_STATUS(AE_NO_MEMORY); | 410 | return_ACPI_STATUS(AE_NO_MEMORY); |
348 | } | 411 | } |
349 | 412 | ||
350 | /* Map the entire table and copy it */ | 413 | /* Read the entire table */ |
351 | 414 | ||
352 | table = acpi_os_map_memory(obj_desc->region.address, length); | 415 | status = acpi_ex_region_read(obj_desc, length, |
353 | if (!table) { | 416 | ACPI_CAST_PTR(u8, |
417 | table_desc.pointer)); | ||
418 | if (ACPI_FAILURE(status)) { | ||
354 | ACPI_FREE(table_desc.pointer); | 419 | ACPI_FREE(table_desc.pointer); |
355 | return_ACPI_STATUS(AE_NO_MEMORY); | 420 | return_ACPI_STATUS(status); |
356 | } | 421 | } |
357 | 422 | ||
358 | ACPI_MEMCPY(table_desc.pointer, table, length); | ||
359 | acpi_os_unmap_memory(table, length); | ||
360 | |||
361 | table_desc.address = obj_desc->region.address; | 423 | table_desc.address = obj_desc->region.address; |
362 | break; | 424 | break; |
363 | 425 | ||
@@ -454,6 +516,10 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, | |||
454 | return_ACPI_STATUS(status); | 516 | return_ACPI_STATUS(status); |
455 | } | 517 | } |
456 | 518 | ||
519 | /* Remove the reference by added by acpi_ex_store above */ | ||
520 | |||
521 | acpi_ut_remove_reference(ddb_handle); | ||
522 | |||
457 | /* Invoke table handler if present */ | 523 | /* Invoke table handler if present */ |
458 | 524 | ||
459 | if (acpi_gbl_table_handler) { | 525 | if (acpi_gbl_table_handler) { |
@@ -495,13 +561,18 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) | |||
495 | 561 | ||
496 | /* | 562 | /* |
497 | * Validate the handle | 563 | * Validate the handle |
498 | * Although the handle is partially validated in acpi_ex_reconfiguration(), | 564 | * Although the handle is partially validated in acpi_ex_reconfiguration() |
499 | * when it calls acpi_ex_resolve_operands(), the handle is more completely | 565 | * when it calls acpi_ex_resolve_operands(), the handle is more completely |
500 | * validated here. | 566 | * validated here. |
567 | * | ||
568 | * Handle must be a valid operand object of type reference. Also, the | ||
569 | * ddb_handle must still be marked valid (table has not been previously | ||
570 | * unloaded) | ||
501 | */ | 571 | */ |
502 | if ((!ddb_handle) || | 572 | if ((!ddb_handle) || |
503 | (ACPI_GET_DESCRIPTOR_TYPE(ddb_handle) != ACPI_DESC_TYPE_OPERAND) || | 573 | (ACPI_GET_DESCRIPTOR_TYPE(ddb_handle) != ACPI_DESC_TYPE_OPERAND) || |
504 | (ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE)) { | 574 | (ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE) || |
575 | (!(ddb_handle->common.flags & AOPOBJ_DATA_VALID))) { | ||
505 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 576 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
506 | } | 577 | } |
507 | 578 | ||
@@ -509,6 +580,12 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) | |||
509 | 580 | ||
510 | table_index = table_desc->reference.value; | 581 | table_index = table_desc->reference.value; |
511 | 582 | ||
583 | /* Ensure the table is still loaded */ | ||
584 | |||
585 | if (!acpi_tb_is_table_loaded(table_index)) { | ||
586 | return_ACPI_STATUS(AE_NOT_EXIST); | ||
587 | } | ||
588 | |||
512 | /* Invoke table handler if present */ | 589 | /* Invoke table handler if present */ |
513 | 590 | ||
514 | if (acpi_gbl_table_handler) { | 591 | if (acpi_gbl_table_handler) { |
@@ -530,8 +607,10 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) | |||
530 | (void)acpi_tb_release_owner_id(table_index); | 607 | (void)acpi_tb_release_owner_id(table_index); |
531 | acpi_tb_set_table_loaded_flag(table_index, FALSE); | 608 | acpi_tb_set_table_loaded_flag(table_index, FALSE); |
532 | 609 | ||
533 | /* Table unloaded, remove a reference to the ddb_handle object */ | 610 | /* |
534 | 611 | * Invalidate the handle. We do this because the handle may be stored | |
535 | acpi_ut_remove_reference(ddb_handle); | 612 | * in a named object and may not be actually deleted until much later. |
613 | */ | ||
614 | ddb_handle->common.flags &= ~AOPOBJ_DATA_VALID; | ||
536 | return_ACPI_STATUS(AE_OK); | 615 | return_ACPI_STATUS(AE_OK); |
537 | } | 616 | } |