diff options
-rw-r--r-- | drivers/acpi/acpica/exconfig.c | 96 |
1 files changed, 78 insertions, 18 deletions
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 0731fd6bad63..eca6f63a53fd 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 |
@@ -257,6 +262,48 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, | |||
257 | 262 | ||
258 | /******************************************************************************* | 263 | /******************************************************************************* |
259 | * | 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 | acpi_physical_address address; | ||
284 | u32 i; | ||
285 | |||
286 | address = obj_desc->region.address; | ||
287 | |||
288 | /* Bytewise reads */ | ||
289 | |||
290 | for (i = 0; i < length; i++) { | ||
291 | status = acpi_ev_address_space_dispatch(obj_desc, ACPI_READ, | ||
292 | address, 8, &value); | ||
293 | if (ACPI_FAILURE(status)) { | ||
294 | return status; | ||
295 | } | ||
296 | |||
297 | *buffer = (u8)value; | ||
298 | buffer++; | ||
299 | address++; | ||
300 | } | ||
301 | |||
302 | return AE_OK; | ||
303 | } | ||
304 | |||
305 | /******************************************************************************* | ||
306 | * | ||
260 | * FUNCTION: acpi_ex_load_op | 307 | * FUNCTION: acpi_ex_load_op |
261 | * | 308 | * |
262 | * PARAMETERS: obj_desc - Region or Buffer/Field where the table will be | 309 | * PARAMETERS: obj_desc - Region or Buffer/Field where the table will be |
@@ -317,18 +364,23 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, | |||
317 | } | 364 | } |
318 | } | 365 | } |
319 | 366 | ||
320 | /* | 367 | /* Get the table header first so we can get the table length */ |
321 | * Map the table header and get the actual table length. The region | 368 | |
322 | * length is not guaranteed to be the same as the table length. | 369 | table = ACPI_ALLOCATE(sizeof(struct acpi_table_header)); |
323 | */ | ||
324 | table = acpi_os_map_memory(obj_desc->region.address, | ||
325 | sizeof(struct acpi_table_header)); | ||
326 | if (!table) { | 370 | if (!table) { |
327 | return_ACPI_STATUS(AE_NO_MEMORY); | 371 | return_ACPI_STATUS(AE_NO_MEMORY); |
328 | } | 372 | } |
329 | 373 | ||
374 | status = | ||
375 | acpi_ex_region_read(obj_desc, | ||
376 | sizeof(struct acpi_table_header), | ||
377 | ACPI_CAST_PTR(u8, table)); | ||
330 | length = table->length; | 378 | length = table->length; |
331 | acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); | 379 | ACPI_FREE(table); |
380 | |||
381 | if (ACPI_FAILURE(status)) { | ||
382 | return_ACPI_STATUS(status); | ||
383 | } | ||
332 | 384 | ||
333 | /* Must have at least an ACPI table header */ | 385 | /* Must have at least an ACPI table header */ |
334 | 386 | ||
@@ -337,10 +389,19 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, | |||
337 | } | 389 | } |
338 | 390 | ||
339 | /* | 391 | /* |
340 | * The memory region is not guaranteed to remain stable and we must | 392 | * The original implementation simply mapped the table, with no copy. |
341 | * copy the table to a local buffer. For example, the memory region | 393 | * However, the memory region is not guaranteed to remain stable and |
342 | * is corrupted after suspend on some machines. Dynamically loaded | 394 | * we must copy the table to a local buffer. For example, the memory |
343 | * tables are usually small, so this overhead is minimal. | 395 | * region is corrupted after suspend on some machines. Dynamically |
396 | * loaded tables are usually small, so this overhead is minimal. | ||
397 | * | ||
398 | * The latest implementation (5/2009) does not use a mapping at all. | ||
399 | * We use the low-level operation region interface to read the table | ||
400 | * instead of the obvious optimization of using a direct mapping. | ||
401 | * This maintains a consistent use of operation regions across the | ||
402 | * entire subsystem. This is important if additional processing must | ||
403 | * be performed in the (possibly user-installed) operation region | ||
404 | * handler. For example, acpi_exec and ASLTS depend on this. | ||
344 | */ | 405 | */ |
345 | 406 | ||
346 | /* Allocate a buffer for the table */ | 407 | /* Allocate a buffer for the table */ |
@@ -350,17 +411,16 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, | |||
350 | return_ACPI_STATUS(AE_NO_MEMORY); | 411 | return_ACPI_STATUS(AE_NO_MEMORY); |
351 | } | 412 | } |
352 | 413 | ||
353 | /* Map the entire table and copy it */ | 414 | /* Read the entire table */ |
354 | 415 | ||
355 | table = acpi_os_map_memory(obj_desc->region.address, length); | 416 | status = acpi_ex_region_read(obj_desc, length, |
356 | if (!table) { | 417 | ACPI_CAST_PTR(u8, |
418 | table_desc.pointer)); | ||
419 | if (ACPI_FAILURE(status)) { | ||
357 | ACPI_FREE(table_desc.pointer); | 420 | ACPI_FREE(table_desc.pointer); |
358 | return_ACPI_STATUS(AE_NO_MEMORY); | 421 | return_ACPI_STATUS(status); |
359 | } | 422 | } |
360 | 423 | ||
361 | ACPI_MEMCPY(table_desc.pointer, table, length); | ||
362 | acpi_os_unmap_memory(table, length); | ||
363 | |||
364 | table_desc.address = obj_desc->region.address; | 424 | table_desc.address = obj_desc->region.address; |
365 | break; | 425 | break; |
366 | 426 | ||