diff options
| -rw-r--r-- | drivers/acpi/tables/tbfadt.c | 125 | ||||
| -rw-r--r-- | include/acpi/acglobal.h | 6 | ||||
| -rw-r--r-- | include/acpi/actypes.h | 8 |
3 files changed, 118 insertions, 21 deletions
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c index 57e089faff1f..b4ce2074c91f 100644 --- a/drivers/acpi/tables/tbfadt.c +++ b/drivers/acpi/tables/tbfadt.c | |||
| @@ -51,7 +51,7 @@ ACPI_MODULE_NAME("tbfadt") | |||
| 51 | /* Local prototypes */ | 51 | /* Local prototypes */ |
| 52 | static inline void | 52 | static inline void |
| 53 | acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, | 53 | acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, |
| 54 | u8 byte_width, u64 address); | 54 | u8 space_id, u8 byte_width, u64 address); |
| 55 | 55 | ||
| 56 | static void acpi_tb_convert_fadt(void); | 56 | static void acpi_tb_convert_fadt(void); |
| 57 | 57 | ||
| @@ -125,7 +125,7 @@ static struct acpi_fadt_info fadt_info_table[] = { | |||
| 125 | 125 | ||
| 126 | static inline void | 126 | static inline void |
| 127 | acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, | 127 | acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, |
| 128 | u8 byte_width, u64 address) | 128 | u8 space_id, u8 byte_width, u64 address) |
| 129 | { | 129 | { |
| 130 | 130 | ||
| 131 | /* | 131 | /* |
| @@ -136,10 +136,10 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, | |||
| 136 | 136 | ||
| 137 | /* All other fields are byte-wide */ | 137 | /* All other fields are byte-wide */ |
| 138 | 138 | ||
| 139 | generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO; | 139 | generic_address->space_id = space_id; |
| 140 | generic_address->bit_width = byte_width << 3; | 140 | generic_address->bit_width = (u8)ACPI_MUL_8(byte_width); |
| 141 | generic_address->bit_offset = 0; | 141 | generic_address->bit_offset = 0; |
| 142 | generic_address->access_width = 0; | 142 | generic_address->access_width = 0; /* Access width ANY */ |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | /******************************************************************************* | 145 | /******************************************************************************* |
| @@ -226,7 +226,8 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) | |||
| 226 | */ | 226 | */ |
| 227 | if (length > sizeof(struct acpi_table_fadt)) { | 227 | if (length > sizeof(struct acpi_table_fadt)) { |
| 228 | ACPI_WARNING((AE_INFO, | 228 | ACPI_WARNING((AE_INFO, |
| 229 | "FADT (revision %u) is longer than ACPI 2.0 version, truncating length 0x%X to 0x%zX", | 229 | "FADT (revision %u) is longer than ACPI 2.0 version, " |
| 230 | "truncating length 0x%X to 0x%zX", | ||
| 230 | table->revision, (unsigned)length, | 231 | table->revision, (unsigned)length, |
| 231 | sizeof(struct acpi_table_fadt))); | 232 | sizeof(struct acpi_table_fadt))); |
| 232 | } | 233 | } |
| @@ -245,7 +246,6 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) | |||
| 245 | * 2) Validate some of the important values within the FADT | 246 | * 2) Validate some of the important values within the FADT |
| 246 | */ | 247 | */ |
| 247 | acpi_tb_convert_fadt(); | 248 | acpi_tb_convert_fadt(); |
| 248 | acpi_tb_validate_fadt(); | ||
| 249 | } | 249 | } |
| 250 | 250 | ||
| 251 | /******************************************************************************* | 251 | /******************************************************************************* |
| @@ -337,7 +337,11 @@ static void acpi_tb_convert_fadt(void) | |||
| 337 | /* Expand only if the X target is null */ | 337 | /* Expand only if the X target is null */ |
| 338 | 338 | ||
| 339 | if (!target->address) { | 339 | if (!target->address) { |
| 340 | |||
| 341 | /* The space_id is always I/O for the legacy address fields */ | ||
| 342 | |||
| 340 | acpi_tb_init_generic_address(target, | 343 | acpi_tb_init_generic_address(target, |
| 344 | ACPI_ADR_SPACE_SYSTEM_IO, | ||
| 341 | *ACPI_ADD_PTR(u8, | 345 | *ACPI_ADD_PTR(u8, |
| 342 | &acpi_gbl_FADT, | 346 | &acpi_gbl_FADT, |
| 343 | fadt_info_table | 347 | fadt_info_table |
| @@ -350,6 +354,25 @@ static void acpi_tb_convert_fadt(void) | |||
| 350 | } | 354 | } |
| 351 | } | 355 | } |
| 352 | 356 | ||
| 357 | /* Validate FADT values now, before we make any changes */ | ||
| 358 | |||
| 359 | acpi_tb_validate_fadt(); | ||
| 360 | |||
| 361 | /* | ||
| 362 | * Get the length of the individual PM1 registers. Each register is | ||
| 363 | * defined to be the event block length / 2. | ||
| 364 | */ | ||
| 365 | pm1_register_length = (u8)ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length); | ||
| 366 | |||
| 367 | /* | ||
| 368 | * Adjust the lengths of the PM1 Event Blocks so that they can be used to | ||
| 369 | * access the PM1 status register(s). | ||
| 370 | */ | ||
| 371 | acpi_gbl_FADT.xpm1a_event_block.bit_width = | ||
| 372 | (u8)ACPI_MUL_8(pm1_register_length); | ||
| 373 | acpi_gbl_FADT.xpm1b_event_block.bit_width = | ||
| 374 | (u8)ACPI_MUL_8(pm1_register_length); | ||
| 375 | |||
| 353 | /* | 376 | /* |
| 354 | * Calculate separate GAS structs for the PM1 Enable registers. | 377 | * Calculate separate GAS structs for the PM1 Enable registers. |
| 355 | * These addresses do not appear (directly) in the FADT, so it is | 378 | * These addresses do not appear (directly) in the FADT, so it is |
| @@ -370,11 +393,11 @@ static void acpi_tb_convert_fadt(void) | |||
| 370 | " PM1_EVT_LEN (%u)\n", | 393 | " PM1_EVT_LEN (%u)\n", |
| 371 | acpi_gbl_FADT.xpm1a_event_block.bit_width, | 394 | acpi_gbl_FADT.xpm1a_event_block.bit_width, |
| 372 | acpi_gbl_FADT.pm1_event_length); | 395 | acpi_gbl_FADT.pm1_event_length); |
| 373 | pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length); | ||
| 374 | 396 | ||
| 375 | /* The PM1A register block is required */ | 397 | /* The PM1A register block is required */ |
| 376 | 398 | ||
| 377 | acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable, | 399 | acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable, |
| 400 | acpi_gbl_FADT.xpm1a_event_block.space_id, | ||
| 378 | pm1_register_length, | 401 | pm1_register_length, |
| 379 | (acpi_gbl_FADT.xpm1a_event_block.address + | 402 | (acpi_gbl_FADT.xpm1a_event_block.address + |
| 380 | pm1_register_length)); | 403 | pm1_register_length)); |
| @@ -393,6 +416,7 @@ static void acpi_tb_convert_fadt(void) | |||
| 393 | acpi_gbl_FADT.xpm1b_event_block.bit_width, | 416 | acpi_gbl_FADT.xpm1b_event_block.bit_width, |
| 394 | acpi_gbl_FADT.pm1_event_length); | 417 | acpi_gbl_FADT.pm1_event_length); |
| 395 | acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable, | 418 | acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable, |
| 419 | acpi_gbl_FADT.xpm1b_event_block.space_id, | ||
| 396 | pm1_register_length, | 420 | pm1_register_length, |
| 397 | (acpi_gbl_FADT.xpm1b_event_block. | 421 | (acpi_gbl_FADT.xpm1b_event_block. |
| 398 | address + pm1_register_length)); | 422 | address + pm1_register_length)); |
| @@ -401,6 +425,30 @@ static void acpi_tb_convert_fadt(void) | |||
| 401 | acpi_gbl_FADT.xpm1b_event_block.space_id; | 425 | acpi_gbl_FADT.xpm1b_event_block.space_id; |
| 402 | 426 | ||
| 403 | } | 427 | } |
| 428 | |||
| 429 | if (acpi_gbl_use_default_register_widths) { | ||
| 430 | /* | ||
| 431 | * Optionally, use the default sizes for the ACPI registers. | ||
| 432 | * Some FADTs do not have the correct length(s). | ||
| 433 | * | ||
| 434 | * Note: Xpm1a_event_block and Xpm1b_event_block are used to access the PM1 | ||
| 435 | * status registers. The PM1 enable registers are created above. | ||
| 436 | */ | ||
| 437 | acpi_gbl_xpm1a_enable.bit_width = ACPI_PM1_REGISTER_WIDTH; | ||
| 438 | acpi_gbl_xpm1b_enable.bit_width = ACPI_PM1_REGISTER_WIDTH; | ||
| 439 | |||
| 440 | acpi_gbl_FADT.xpm1a_event_block.bit_width = | ||
| 441 | ACPI_PM1_REGISTER_WIDTH; | ||
| 442 | acpi_gbl_FADT.xpm1b_event_block.bit_width = | ||
| 443 | ACPI_PM1_REGISTER_WIDTH; | ||
| 444 | acpi_gbl_FADT.xpm1a_control_block.bit_width = | ||
| 445 | ACPI_PM1_REGISTER_WIDTH; | ||
| 446 | acpi_gbl_FADT.xpm1b_control_block.bit_width = | ||
| 447 | ACPI_PM1_REGISTER_WIDTH; | ||
| 448 | acpi_gbl_FADT.xpm2_control_block.bit_width = | ||
| 449 | ACPI_PM2_REGISTER_WIDTH; | ||
| 450 | acpi_gbl_FADT.xpm_timer_block.bit_width = ACPI_PM_TIMER_WIDTH; | ||
| 451 | } | ||
| 404 | } | 452 | } |
| 405 | 453 | ||
| 406 | /****************************************************************************** | 454 | /****************************************************************************** |
| @@ -425,26 +473,63 @@ static void acpi_tb_convert_fadt(void) | |||
| 425 | 473 | ||
| 426 | static void acpi_tb_validate_fadt(void) | 474 | static void acpi_tb_validate_fadt(void) |
| 427 | { | 475 | { |
| 476 | char *name; | ||
| 428 | u32 *address32; | 477 | u32 *address32; |
| 429 | struct acpi_generic_address *address64; | 478 | struct acpi_generic_address *address64; |
| 430 | u8 length; | 479 | u8 length; |
| 431 | u32 i; | 480 | u32 i; |
| 432 | 481 | ||
| 433 | /* Examine all of the 64-bit extended address fields (X fields) */ | 482 | /* |
| 483 | * Check for FACS and DSDT address mismatches. An address mismatch between | ||
| 484 | * the 32-bit and 64-bit address fields (FIRMWARE_CTRL/X_FIRMWARE_CTRL and | ||
| 485 | * DSDT/X_DSDT) would indicate the presence of two FACS or two DSDT tables. | ||
| 486 | */ | ||
| 487 | if (acpi_gbl_FADT.facs && | ||
| 488 | (acpi_gbl_FADT.Xfacs != (u64) acpi_gbl_FADT.facs)) { | ||
| 489 | ACPI_WARNING((AE_INFO, | ||
| 490 | "32/64 FACS address mismatch in FADT - " | ||
| 491 | "two FACS tables! %8.8X/%8.8X%8.8X", | ||
| 492 | acpi_gbl_FADT.facs, | ||
| 493 | ACPI_FORMAT_UINT64(acpi_gbl_FADT.Xfacs))); | ||
| 494 | } | ||
| 434 | 495 | ||
| 435 | for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { | 496 | if (acpi_gbl_FADT.dsdt && |
| 497 | (acpi_gbl_FADT.Xdsdt != (u64) acpi_gbl_FADT.dsdt)) { | ||
| 498 | ACPI_WARNING((AE_INFO, | ||
| 499 | "32/64 DSDT address mismatch in FADT - " | ||
| 500 | "two DSDT tables! %8.8X/%8.8X%8.8X", | ||
| 501 | acpi_gbl_FADT.dsdt, | ||
| 502 | ACPI_FORMAT_UINT64(acpi_gbl_FADT.Xdsdt))); | ||
| 503 | } | ||
| 436 | 504 | ||
| 437 | /* Generate pointers to the 32-bit and 64-bit addresses and get the length */ | 505 | /* Examine all of the 64-bit extended address fields (X fields) */ |
| 438 | 506 | ||
| 439 | address64 = | 507 | for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { |
| 440 | ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, | 508 | /* |
| 441 | fadt_info_table[i].target); | 509 | * Generate pointers to the 32-bit and 64-bit addresses, get the |
| 510 | * register length (width), and the register name | ||
| 511 | */ | ||
| 512 | address64 = ACPI_ADD_PTR(struct acpi_generic_address, | ||
| 513 | &acpi_gbl_FADT, | ||
| 514 | fadt_info_table[i].target); | ||
| 442 | address32 = | 515 | address32 = |
| 443 | ACPI_ADD_PTR(u32, &acpi_gbl_FADT, | 516 | ACPI_ADD_PTR(u32, &acpi_gbl_FADT, |
| 444 | fadt_info_table[i].source); | 517 | fadt_info_table[i].source); |
| 445 | length = | 518 | length = |
| 446 | *ACPI_ADD_PTR(u8, &acpi_gbl_FADT, | 519 | *ACPI_ADD_PTR(u8, &acpi_gbl_FADT, |
| 447 | fadt_info_table[i].length); | 520 | fadt_info_table[i].length); |
| 521 | name = fadt_info_table[i].name; | ||
| 522 | |||
| 523 | /* | ||
| 524 | * For each extended field, check for length mismatch between the | ||
| 525 | * legacy length field and the corresonding 64-bit X length field. | ||
| 526 | */ | ||
| 527 | if (address64 && (address64->bit_width != ACPI_MUL_8(length))) { | ||
| 528 | ACPI_WARNING((AE_INFO, | ||
| 529 | "32/64X bit length mismatch in %s: %d/%d", | ||
| 530 | name, ACPI_MUL_8(length), | ||
| 531 | address64->bit_width)); | ||
| 532 | } | ||
| 448 | 533 | ||
| 449 | if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) { | 534 | if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) { |
| 450 | /* | 535 | /* |
| @@ -453,8 +538,8 @@ static void acpi_tb_validate_fadt(void) | |||
| 453 | */ | 538 | */ |
| 454 | if (!address64->address || !length) { | 539 | if (!address64->address || !length) { |
| 455 | ACPI_ERROR((AE_INFO, | 540 | ACPI_ERROR((AE_INFO, |
| 456 | "Required field \"%s\" has zero address and/or length: %8.8X%8.8X/%X", | 541 | "Required field %s has zero address and/or length: %8.8X%8.8X/%X", |
| 457 | fadt_info_table[i].name, | 542 | name, |
| 458 | ACPI_FORMAT_UINT64(address64-> | 543 | ACPI_FORMAT_UINT64(address64-> |
| 459 | address), | 544 | address), |
| 460 | length)); | 545 | length)); |
| @@ -467,8 +552,8 @@ static void acpi_tb_validate_fadt(void) | |||
| 467 | if ((address64->address && !length) | 552 | if ((address64->address && !length) |
| 468 | || (!address64->address && length)) { | 553 | || (!address64->address && length)) { |
| 469 | ACPI_WARNING((AE_INFO, | 554 | ACPI_WARNING((AE_INFO, |
| 470 | "Optional field \"%s\" has zero address or length: %8.8X%8.8X/%X", | 555 | "Optional field %s has zero address or length: %8.8X%8.8X/%X", |
| 471 | fadt_info_table[i].name, | 556 | name, |
| 472 | ACPI_FORMAT_UINT64(address64-> | 557 | ACPI_FORMAT_UINT64(address64-> |
| 473 | address), | 558 | address), |
| 474 | length)); | 559 | length)); |
| @@ -480,8 +565,8 @@ static void acpi_tb_validate_fadt(void) | |||
| 480 | if (address64->address && *address32 && | 565 | if (address64->address && *address32 && |
| 481 | (address64->address != (u64) * address32)) { | 566 | (address64->address != (u64) * address32)) { |
| 482 | ACPI_ERROR((AE_INFO, | 567 | ACPI_ERROR((AE_INFO, |
| 483 | "32/64X address mismatch in \"%s\": [%8.8X] [%8.8X%8.8X], using 64X", | 568 | "32/64X address mismatch in %s: [%8.8X] [%8.8X%8.8X], using 64X", |
| 484 | fadt_info_table[i].name, *address32, | 569 | name, *address32, |
| 485 | ACPI_FORMAT_UINT64(address64->address))); | 570 | ACPI_FORMAT_UINT64(address64->address))); |
| 486 | } | 571 | } |
| 487 | } | 572 | } |
diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h index 78f3c149f7ba..55eb5d618764 100644 --- a/include/acpi/acglobal.h +++ b/include/acpi/acglobal.h | |||
| @@ -102,6 +102,12 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_create_osi_method, TRUE); | |||
| 102 | */ | 102 | */ |
| 103 | ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE); | 103 | ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE); |
| 104 | 104 | ||
| 105 | /* | ||
| 106 | * Optionally use default values for the ACPI register widths. Set this to | ||
| 107 | * TRUE to use the defaults, if an FADT contains incorrect widths/lengths. | ||
| 108 | */ | ||
| 109 | ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, FALSE); | ||
| 110 | |||
| 105 | /***************************************************************************** | 111 | /***************************************************************************** |
| 106 | * | 112 | * |
| 107 | * Debug support | 113 | * Debug support |
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 24b2cef5a13f..03744d28dcf6 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h | |||
| @@ -309,10 +309,16 @@ typedef u32 acpi_physical_address; | |||
| 309 | * | 309 | * |
| 310 | *****************************************************************************/ | 310 | *****************************************************************************/ |
| 311 | 311 | ||
| 312 | /* Number of distinct GPE register blocks and register width */ | 312 | /* Number of distinct FADT-based GPE register blocks (GPE0 and GPE1) */ |
| 313 | 313 | ||
| 314 | #define ACPI_MAX_GPE_BLOCKS 2 | 314 | #define ACPI_MAX_GPE_BLOCKS 2 |
| 315 | |||
| 316 | /* Default ACPI register widths */ | ||
| 317 | |||
| 315 | #define ACPI_GPE_REGISTER_WIDTH 8 | 318 | #define ACPI_GPE_REGISTER_WIDTH 8 |
| 319 | #define ACPI_PM1_REGISTER_WIDTH 16 | ||
| 320 | #define ACPI_PM2_REGISTER_WIDTH 8 | ||
| 321 | #define ACPI_PM_TIMER_WIDTH 32 | ||
| 316 | 322 | ||
| 317 | /* Names within the namespace are 4 bytes long */ | 323 | /* Names within the namespace are 4 bytes long */ |
| 318 | 324 | ||
