diff options
author | Bob Moore <robert.moore@intel.com> | 2009-02-18 01:06:12 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-03-26 16:38:22 -0400 |
commit | 531c633d2be8e79087335a46d3c017ca5837e588 (patch) | |
tree | 603476b57482a8b728a8c218f3a53bf44076b85c /drivers/acpi/acpica/tbfadt.c | |
parent | 6fc69d8beb0c16311f737df2c6f677057d50ab05 (diff) |
ACPICA: Split out PM1 status registers from the FADT
Add new globals for the PM1 status registers (A/B), similar to the
way the PM1 enable registers are handled. Instead of overloading
the FADT Event Register blocks. This makes the code clearer and
less prone to error.
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/acpica/tbfadt.c')
-rw-r--r-- | drivers/acpi/acpica/tbfadt.c | 246 |
1 files changed, 133 insertions, 113 deletions
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 4b683ccd4a94..a8191efd9aa6 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c | |||
@@ -57,6 +57,8 @@ static void acpi_tb_convert_fadt(void); | |||
57 | 57 | ||
58 | static void acpi_tb_validate_fadt(void); | 58 | static void acpi_tb_validate_fadt(void); |
59 | 59 | ||
60 | static void acpi_tb_setup_fadt_registers(void); | ||
61 | |||
60 | /* Table for conversion of FADT to common internal format and FADT validation */ | 62 | /* Table for conversion of FADT to common internal format and FADT validation */ |
61 | 63 | ||
62 | typedef struct acpi_fadt_info { | 64 | typedef struct acpi_fadt_info { |
@@ -132,6 +134,35 @@ static struct acpi_fadt_info fadt_info_table[] = { | |||
132 | 134 | ||
133 | #define ACPI_FADT_INFO_ENTRIES (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info)) | 135 | #define ACPI_FADT_INFO_ENTRIES (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info)) |
134 | 136 | ||
137 | /* Table used to split Event Blocks into separate status/enable registers */ | ||
138 | |||
139 | typedef struct acpi_fadt_pm_info { | ||
140 | struct acpi_generic_address *target; | ||
141 | u8 source; | ||
142 | u8 register_num; | ||
143 | |||
144 | } acpi_fadt_pm_info; | ||
145 | |||
146 | static struct acpi_fadt_pm_info fadt_pm_info_table[] = { | ||
147 | {&acpi_gbl_xpm1a_status, | ||
148 | ACPI_FADT_OFFSET(xpm1a_event_block), | ||
149 | 0}, | ||
150 | |||
151 | {&acpi_gbl_xpm1a_enable, | ||
152 | ACPI_FADT_OFFSET(xpm1a_event_block), | ||
153 | 1}, | ||
154 | |||
155 | {&acpi_gbl_xpm1b_status, | ||
156 | ACPI_FADT_OFFSET(xpm1b_event_block), | ||
157 | 0}, | ||
158 | |||
159 | {&acpi_gbl_xpm1b_enable, | ||
160 | ACPI_FADT_OFFSET(xpm1b_event_block), | ||
161 | 1} | ||
162 | }; | ||
163 | |||
164 | #define ACPI_FADT_PM_INFO_ENTRIES (sizeof (fadt_pm_info_table) / sizeof (struct acpi_fadt_pm_info)) | ||
165 | |||
135 | /******************************************************************************* | 166 | /******************************************************************************* |
136 | * | 167 | * |
137 | * FUNCTION: acpi_tb_init_generic_address | 168 | * FUNCTION: acpi_tb_init_generic_address |
@@ -207,7 +238,7 @@ void acpi_tb_parse_fadt(u32 table_index) | |||
207 | */ | 238 | */ |
208 | (void)acpi_tb_verify_checksum(table, length); | 239 | (void)acpi_tb_verify_checksum(table, length); |
209 | 240 | ||
210 | /* Obtain a local copy of the FADT in common ACPI 2.0+ format */ | 241 | /* Create a local copy of the FADT in common ACPI 2.0+ format */ |
211 | 242 | ||
212 | acpi_tb_create_local_fadt(table, length); | 243 | acpi_tb_create_local_fadt(table, length); |
213 | 244 | ||
@@ -265,11 +296,17 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) | |||
265 | ACPI_MEMCPY(&acpi_gbl_FADT, table, | 296 | ACPI_MEMCPY(&acpi_gbl_FADT, table, |
266 | ACPI_MIN(length, sizeof(struct acpi_table_fadt))); | 297 | ACPI_MIN(length, sizeof(struct acpi_table_fadt))); |
267 | 298 | ||
268 | /* | 299 | /* Convert the local copy of the FADT to the common internal format */ |
269 | * 1) Convert the local copy of the FADT to the common internal format | 300 | |
270 | * 2) Validate some of the important values within the FADT | ||
271 | */ | ||
272 | acpi_tb_convert_fadt(); | 301 | acpi_tb_convert_fadt(); |
302 | |||
303 | /* Validate FADT values now, before we make any changes */ | ||
304 | |||
305 | acpi_tb_validate_fadt(); | ||
306 | |||
307 | /* Initialize the global ACPI register structures */ | ||
308 | |||
309 | acpi_tb_setup_fadt_registers(); | ||
273 | } | 310 | } |
274 | 311 | ||
275 | /******************************************************************************* | 312 | /******************************************************************************* |
@@ -303,8 +340,6 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) | |||
303 | 340 | ||
304 | static void acpi_tb_convert_fadt(void) | 341 | static void acpi_tb_convert_fadt(void) |
305 | { | 342 | { |
306 | u8 pm1_register_bit_width; | ||
307 | u8 pm1_register_byte_width; | ||
308 | struct acpi_generic_address *target64; | 343 | struct acpi_generic_address *target64; |
309 | u32 i; | 344 | u32 i; |
310 | 345 | ||
@@ -379,112 +414,6 @@ static void acpi_tb_convert_fadt(void) | |||
379 | address32)); | 414 | address32)); |
380 | } | 415 | } |
381 | } | 416 | } |
382 | |||
383 | /* Validate FADT values now, before we make any changes */ | ||
384 | |||
385 | acpi_tb_validate_fadt(); | ||
386 | |||
387 | /* | ||
388 | * Optionally check all register lengths against the default values and | ||
389 | * update them if they are incorrect. | ||
390 | */ | ||
391 | if (acpi_gbl_use_default_register_widths) { | ||
392 | for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { | ||
393 | target64 = | ||
394 | ACPI_ADD_PTR(struct acpi_generic_address, | ||
395 | &acpi_gbl_FADT, | ||
396 | fadt_info_table[i].address64); | ||
397 | |||
398 | /* | ||
399 | * If a valid register (Address != 0) and the (default_length > 0) | ||
400 | * (Not a GPE register), then check the width against the default. | ||
401 | */ | ||
402 | if ((target64->address) && | ||
403 | (fadt_info_table[i].default_length > 0) && | ||
404 | (fadt_info_table[i].default_length != | ||
405 | target64->bit_width)) { | ||
406 | ACPI_WARNING((AE_INFO, | ||
407 | "Invalid length for %s: %d, using default %d", | ||
408 | fadt_info_table[i].name, | ||
409 | target64->bit_width, | ||
410 | fadt_info_table[i]. | ||
411 | default_length)); | ||
412 | |||
413 | /* Incorrect size, set width to the default */ | ||
414 | |||
415 | target64->bit_width = | ||
416 | fadt_info_table[i].default_length; | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | |||
421 | /* | ||
422 | * Get the length of the individual PM1 registers (enable and status). | ||
423 | * Each register is defined to be (event block length / 2). | ||
424 | */ | ||
425 | pm1_register_bit_width = | ||
426 | (u8)ACPI_DIV_2(acpi_gbl_FADT.xpm1a_event_block.bit_width); | ||
427 | pm1_register_byte_width = (u8)ACPI_DIV_8(pm1_register_bit_width); | ||
428 | |||
429 | /* | ||
430 | * Adjust the lengths of the PM1 Event Blocks so that they can be used to | ||
431 | * access the PM1 status register(s). Use (width / 2) | ||
432 | */ | ||
433 | acpi_gbl_FADT.xpm1a_event_block.bit_width = pm1_register_bit_width; | ||
434 | acpi_gbl_FADT.xpm1b_event_block.bit_width = pm1_register_bit_width; | ||
435 | |||
436 | /* | ||
437 | * Calculate separate GAS structs for the PM1 Enable registers. | ||
438 | * These addresses do not appear (directly) in the FADT, so it is | ||
439 | * useful to calculate them once, here. | ||
440 | * | ||
441 | * The PM event blocks are split into two register blocks, first is the | ||
442 | * PM Status Register block, followed immediately by the PM Enable | ||
443 | * Register block. Each is of length (xpm1x_event_block.bit_width/2). | ||
444 | * | ||
445 | * On various systems the v2 fields (and particularly the bit widths) | ||
446 | * cannot be relied upon, though. Hence resort to using the v1 length | ||
447 | * here (and warn about the inconsistency). | ||
448 | */ | ||
449 | if (acpi_gbl_FADT.xpm1a_event_block.bit_width | ||
450 | != acpi_gbl_FADT.pm1_event_length * 8) | ||
451 | printk(KERN_WARNING "FADT: " | ||
452 | "X_PM1a_EVT_BLK.bit_width (%u) does not match" | ||
453 | " PM1_EVT_LEN (%u)\n", | ||
454 | acpi_gbl_FADT.xpm1a_event_block.bit_width, | ||
455 | acpi_gbl_FADT.pm1_event_length); | ||
456 | |||
457 | /* The PM1A register block is required */ | ||
458 | |||
459 | acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable, | ||
460 | acpi_gbl_FADT.xpm1a_event_block.space_id, | ||
461 | pm1_register_byte_width, | ||
462 | (acpi_gbl_FADT.xpm1a_event_block.address + | ||
463 | pm1_register_byte_width)); | ||
464 | /* Don't forget to copy space_id of the GAS */ | ||
465 | acpi_gbl_xpm1a_enable.space_id = | ||
466 | acpi_gbl_FADT.xpm1a_event_block.space_id; | ||
467 | |||
468 | /* The PM1B register block is optional, ignore if not present */ | ||
469 | |||
470 | if (acpi_gbl_FADT.xpm1b_event_block.address) { | ||
471 | if (acpi_gbl_FADT.xpm1b_event_block.bit_width | ||
472 | != acpi_gbl_FADT.pm1_event_length * 8) | ||
473 | printk(KERN_WARNING "FADT: " | ||
474 | "X_PM1b_EVT_BLK.bit_width (%u) does not match" | ||
475 | " PM1_EVT_LEN (%u)\n", | ||
476 | acpi_gbl_FADT.xpm1b_event_block.bit_width, | ||
477 | acpi_gbl_FADT.pm1_event_length); | ||
478 | acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable, | ||
479 | acpi_gbl_FADT.xpm1b_event_block.space_id, | ||
480 | pm1_register_byte_width, | ||
481 | (acpi_gbl_FADT.xpm1b_event_block. | ||
482 | address + pm1_register_byte_width)); | ||
483 | /* Don't forget to copy space_id of the GAS */ | ||
484 | acpi_gbl_xpm1b_enable.space_id = | ||
485 | acpi_gbl_FADT.xpm1b_event_block.space_id; | ||
486 | |||
487 | } | ||
488 | } | 417 | } |
489 | 418 | ||
490 | /****************************************************************************** | 419 | /****************************************************************************** |
@@ -607,3 +536,94 @@ static void acpi_tb_validate_fadt(void) | |||
607 | } | 536 | } |
608 | } | 537 | } |
609 | } | 538 | } |
539 | |||
540 | /****************************************************************************** | ||
541 | * | ||
542 | * FUNCTION: acpi_tb_setup_fadt_registers | ||
543 | * | ||
544 | * PARAMETERS: None, uses acpi_gbl_FADT. | ||
545 | * | ||
546 | * RETURN: None | ||
547 | * | ||
548 | * DESCRIPTION: Initialize global ACPI PM1 register definitions. Optionally, | ||
549 | * force FADT register definitions to their default lengths. | ||
550 | * | ||
551 | ******************************************************************************/ | ||
552 | |||
553 | static void acpi_tb_setup_fadt_registers(void) | ||
554 | { | ||
555 | struct acpi_generic_address *target64; | ||
556 | struct acpi_generic_address *source64; | ||
557 | u8 pm1_register_byte_width; | ||
558 | u32 i; | ||
559 | |||
560 | /* | ||
561 | * Optionally check all register lengths against the default values and | ||
562 | * update them if they are incorrect. | ||
563 | */ | ||
564 | if (acpi_gbl_use_default_register_widths) { | ||
565 | for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { | ||
566 | target64 = | ||
567 | ACPI_ADD_PTR(struct acpi_generic_address, | ||
568 | &acpi_gbl_FADT, | ||
569 | fadt_info_table[i].address64); | ||
570 | |||
571 | /* | ||
572 | * If a valid register (Address != 0) and the (default_length > 0) | ||
573 | * (Not a GPE register), then check the width against the default. | ||
574 | */ | ||
575 | if ((target64->address) && | ||
576 | (fadt_info_table[i].default_length > 0) && | ||
577 | (fadt_info_table[i].default_length != | ||
578 | target64->bit_width)) { | ||
579 | ACPI_WARNING((AE_INFO, | ||
580 | "Invalid length for %s: %d, using default %d", | ||
581 | fadt_info_table[i].name, | ||
582 | target64->bit_width, | ||
583 | fadt_info_table[i]. | ||
584 | default_length)); | ||
585 | |||
586 | /* Incorrect size, set width to the default */ | ||
587 | |||
588 | target64->bit_width = | ||
589 | fadt_info_table[i].default_length; | ||
590 | } | ||
591 | } | ||
592 | } | ||
593 | |||
594 | /* | ||
595 | * Get the length of the individual PM1 registers (enable and status). | ||
596 | * Each register is defined to be (event block length / 2). Extra divide | ||
597 | * by 8 converts bits to bytes. | ||
598 | */ | ||
599 | pm1_register_byte_width = | ||
600 | (u8)ACPI_DIV_16(acpi_gbl_FADT.xpm1a_event_block.bit_width); | ||
601 | |||
602 | /* | ||
603 | * Calculate separate GAS structs for the PM1x (A/B) Status and Enable | ||
604 | * registers. These addresses do not appear (directly) in the FADT, so it | ||
605 | * is useful to pre-calculate them from the PM1 Event Block definitions. | ||
606 | * | ||
607 | * The PM event blocks are split into two register blocks, first is the | ||
608 | * PM Status Register block, followed immediately by the PM Enable | ||
609 | * Register block. Each is of length (pm1_event_length/2) | ||
610 | * | ||
611 | * Note: The PM1A event block is required by the ACPI specification. | ||
612 | * However, the PM1B event block is optional and is rarely, if ever, | ||
613 | * used. | ||
614 | */ | ||
615 | |||
616 | for (i = 0; i < ACPI_FADT_PM_INFO_ENTRIES; i++) { | ||
617 | source64 = | ||
618 | ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, | ||
619 | fadt_pm_info_table[i].source); | ||
620 | |||
621 | acpi_tb_init_generic_address(fadt_pm_info_table[i].target, | ||
622 | source64->space_id, | ||
623 | pm1_register_byte_width, | ||
624 | source64->address + | ||
625 | (fadt_pm_info_table[i]. | ||
626 | register_num * | ||
627 | pm1_register_byte_width)); | ||
628 | } | ||
629 | } | ||