0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <acpi/acpi.h>
0011 #include "accommon.h"
0012 #include "actables.h"
0013
0014 #define _COMPONENT ACPI_TABLES
0015 ACPI_MODULE_NAME("tbfadt")
0016
0017
0018 static void
0019 acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
0020 u8 space_id,
0021 u8 byte_width,
0022 u64 address, const char *register_name, u8 flags);
0023
0024 static void acpi_tb_convert_fadt(void);
0025
0026 static void acpi_tb_setup_fadt_registers(void);
0027
0028 static u64
0029 acpi_tb_select_address(char *register_name, u32 address32, u64 address64);
0030
0031
0032
0033 typedef struct acpi_fadt_info {
0034 const char *name;
0035 u16 address64;
0036 u16 address32;
0037 u16 length;
0038 u8 default_length;
0039 u8 flags;
0040
0041 } acpi_fadt_info;
0042
0043 #define ACPI_FADT_OPTIONAL 0
0044 #define ACPI_FADT_REQUIRED 1
0045 #define ACPI_FADT_SEPARATE_LENGTH 2
0046 #define ACPI_FADT_GPE_REGISTER 4
0047
0048 static struct acpi_fadt_info fadt_info_table[] = {
0049 {"Pm1aEventBlock",
0050 ACPI_FADT_OFFSET(xpm1a_event_block),
0051 ACPI_FADT_OFFSET(pm1a_event_block),
0052 ACPI_FADT_OFFSET(pm1_event_length),
0053 ACPI_PM1_REGISTER_WIDTH * 2,
0054 ACPI_FADT_REQUIRED},
0055
0056 {"Pm1bEventBlock",
0057 ACPI_FADT_OFFSET(xpm1b_event_block),
0058 ACPI_FADT_OFFSET(pm1b_event_block),
0059 ACPI_FADT_OFFSET(pm1_event_length),
0060 ACPI_PM1_REGISTER_WIDTH * 2,
0061 ACPI_FADT_OPTIONAL},
0062
0063 {"Pm1aControlBlock",
0064 ACPI_FADT_OFFSET(xpm1a_control_block),
0065 ACPI_FADT_OFFSET(pm1a_control_block),
0066 ACPI_FADT_OFFSET(pm1_control_length),
0067 ACPI_PM1_REGISTER_WIDTH,
0068 ACPI_FADT_REQUIRED},
0069
0070 {"Pm1bControlBlock",
0071 ACPI_FADT_OFFSET(xpm1b_control_block),
0072 ACPI_FADT_OFFSET(pm1b_control_block),
0073 ACPI_FADT_OFFSET(pm1_control_length),
0074 ACPI_PM1_REGISTER_WIDTH,
0075 ACPI_FADT_OPTIONAL},
0076
0077 {"Pm2ControlBlock",
0078 ACPI_FADT_OFFSET(xpm2_control_block),
0079 ACPI_FADT_OFFSET(pm2_control_block),
0080 ACPI_FADT_OFFSET(pm2_control_length),
0081 ACPI_PM2_REGISTER_WIDTH,
0082 ACPI_FADT_SEPARATE_LENGTH},
0083
0084 {"PmTimerBlock",
0085 ACPI_FADT_OFFSET(xpm_timer_block),
0086 ACPI_FADT_OFFSET(pm_timer_block),
0087 ACPI_FADT_OFFSET(pm_timer_length),
0088 ACPI_PM_TIMER_WIDTH,
0089 ACPI_FADT_SEPARATE_LENGTH},
0090
0091 {"Gpe0Block",
0092 ACPI_FADT_OFFSET(xgpe0_block),
0093 ACPI_FADT_OFFSET(gpe0_block),
0094 ACPI_FADT_OFFSET(gpe0_block_length),
0095 0,
0096 ACPI_FADT_SEPARATE_LENGTH | ACPI_FADT_GPE_REGISTER},
0097
0098 {"Gpe1Block",
0099 ACPI_FADT_OFFSET(xgpe1_block),
0100 ACPI_FADT_OFFSET(gpe1_block),
0101 ACPI_FADT_OFFSET(gpe1_block_length),
0102 0,
0103 ACPI_FADT_SEPARATE_LENGTH | ACPI_FADT_GPE_REGISTER}
0104 };
0105
0106 #define ACPI_FADT_INFO_ENTRIES \
0107 (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info))
0108
0109
0110
0111 typedef struct acpi_fadt_pm_info {
0112 struct acpi_generic_address *target;
0113 u16 source;
0114 u8 register_num;
0115
0116 } acpi_fadt_pm_info;
0117
0118 static struct acpi_fadt_pm_info fadt_pm_info_table[] = {
0119 {&acpi_gbl_xpm1a_status,
0120 ACPI_FADT_OFFSET(xpm1a_event_block),
0121 0},
0122
0123 {&acpi_gbl_xpm1a_enable,
0124 ACPI_FADT_OFFSET(xpm1a_event_block),
0125 1},
0126
0127 {&acpi_gbl_xpm1b_status,
0128 ACPI_FADT_OFFSET(xpm1b_event_block),
0129 0},
0130
0131 {&acpi_gbl_xpm1b_enable,
0132 ACPI_FADT_OFFSET(xpm1b_event_block),
0133 1}
0134 };
0135
0136 #define ACPI_FADT_PM_INFO_ENTRIES \
0137 (sizeof (fadt_pm_info_table) / sizeof (struct acpi_fadt_pm_info))
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157 static void
0158 acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
0159 u8 space_id,
0160 u8 byte_width,
0161 u64 address, const char *register_name, u8 flags)
0162 {
0163 u8 bit_width;
0164
0165
0166
0167
0168
0169 bit_width = (u8)(byte_width * 8);
0170 if (byte_width > 31) {
0171
0172
0173
0174
0175
0176 if (!(flags & ACPI_FADT_GPE_REGISTER)) {
0177 ACPI_ERROR((AE_INFO,
0178 "%s - 32-bit FADT register is too long (%u bytes, %u bits) "
0179 "to convert to GAS struct - 255 bits max, truncating",
0180 register_name, byte_width,
0181 (byte_width * 8)));
0182 }
0183
0184 bit_width = 255;
0185 }
0186
0187
0188
0189
0190
0191 ACPI_MOVE_64_TO_64(&generic_address->address, &address);
0192
0193
0194
0195 generic_address->space_id = space_id;
0196 generic_address->bit_width = bit_width;
0197 generic_address->bit_offset = 0;
0198 generic_address->access_width = 0;
0199 }
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228 static u64
0229 acpi_tb_select_address(char *register_name, u32 address32, u64 address64)
0230 {
0231
0232 if (!address64) {
0233
0234
0235
0236 return ((u64)address32);
0237 }
0238
0239 if (address32 && (address64 != (u64)address32)) {
0240
0241
0242
0243 ACPI_BIOS_WARNING((AE_INFO,
0244 "32/64X %s address mismatch in FADT: "
0245 "0x%8.8X/0x%8.8X%8.8X, using %u-bit address",
0246 register_name, address32,
0247 ACPI_FORMAT_UINT64(address64),
0248 acpi_gbl_use32_bit_fadt_addresses ? 32 :
0249 64));
0250
0251
0252
0253 if (acpi_gbl_use32_bit_fadt_addresses) {
0254 return ((u64)address32);
0255 }
0256 }
0257
0258
0259
0260 return (address64);
0261 }
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276 void acpi_tb_parse_fadt(void)
0277 {
0278 u32 length;
0279 struct acpi_table_header *table;
0280 struct acpi_table_desc *fadt_desc;
0281 acpi_status status;
0282
0283
0284
0285
0286
0287
0288
0289
0290 fadt_desc = &acpi_gbl_root_table_list.tables[acpi_gbl_fadt_index];
0291 status = acpi_tb_get_table(fadt_desc, &table);
0292 if (ACPI_FAILURE(status)) {
0293 return;
0294 }
0295 length = fadt_desc->length;
0296
0297
0298
0299
0300
0301 (void)acpi_tb_verify_checksum(table, length);
0302
0303
0304
0305 acpi_tb_create_local_fadt(table, length);
0306
0307
0308
0309 acpi_tb_put_table(fadt_desc);
0310
0311
0312
0313 acpi_tb_install_standard_table((acpi_physical_address)acpi_gbl_FADT.
0314 Xdsdt,
0315 ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,
0316 NULL, FALSE, TRUE, &acpi_gbl_dsdt_index);
0317
0318
0319
0320 if (!acpi_gbl_reduced_hardware) {
0321 if (acpi_gbl_FADT.facs) {
0322 acpi_tb_install_standard_table((acpi_physical_address)
0323 acpi_gbl_FADT.facs,
0324 ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,
0325 NULL, FALSE, TRUE,
0326 &acpi_gbl_facs_index);
0327 }
0328 if (acpi_gbl_FADT.Xfacs) {
0329 acpi_tb_install_standard_table((acpi_physical_address)
0330 acpi_gbl_FADT.Xfacs,
0331 ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,
0332 NULL, FALSE, TRUE,
0333 &acpi_gbl_xfacs_index);
0334 }
0335 }
0336 }
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354 void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
0355 {
0356
0357
0358
0359
0360
0361 if (length > sizeof(struct acpi_table_fadt)) {
0362 ACPI_BIOS_WARNING((AE_INFO,
0363 "FADT (revision %u) is longer than %s length, "
0364 "truncating length %u to %u",
0365 table->revision, ACPI_FADT_CONFORMANCE,
0366 length,
0367 (u32)sizeof(struct acpi_table_fadt)));
0368 }
0369
0370
0371
0372 memset(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt));
0373
0374
0375
0376 memcpy(&acpi_gbl_FADT, table,
0377 ACPI_MIN(length, sizeof(struct acpi_table_fadt)));
0378
0379
0380
0381 acpi_gbl_reduced_hardware = FALSE;
0382 if (acpi_gbl_FADT.flags & ACPI_FADT_HW_REDUCED) {
0383 acpi_gbl_reduced_hardware = TRUE;
0384 }
0385
0386
0387
0388 acpi_tb_convert_fadt();
0389
0390
0391
0392 acpi_tb_setup_fadt_registers();
0393 }
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439 static void acpi_tb_convert_fadt(void)
0440 {
0441 const char *name;
0442 struct acpi_generic_address *address64;
0443 u32 address32;
0444 u8 length;
0445 u8 flags;
0446 u32 i;
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459 if (acpi_gbl_FADT.header.length <= ACPI_FADT_V2_SIZE) {
0460 acpi_gbl_FADT.preferred_profile = 0;
0461 acpi_gbl_FADT.pstate_control = 0;
0462 acpi_gbl_FADT.cst_control = 0;
0463 acpi_gbl_FADT.boot_flags = 0;
0464 }
0465
0466
0467
0468
0469
0470
0471 acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt);
0472
0473
0474
0475
0476
0477 acpi_gbl_FADT.Xdsdt = acpi_tb_select_address("DSDT",
0478 acpi_gbl_FADT.dsdt,
0479 acpi_gbl_FADT.Xdsdt);
0480
0481
0482
0483 if (acpi_gbl_reduced_hardware) {
0484 return;
0485 }
0486
0487
0488
0489 for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
0490
0491
0492
0493
0494 address32 = *ACPI_ADD_PTR(u32,
0495 &acpi_gbl_FADT,
0496 fadt_info_table[i].address32);
0497
0498 address64 = ACPI_ADD_PTR(struct acpi_generic_address,
0499 &acpi_gbl_FADT,
0500 fadt_info_table[i].address64);
0501
0502 length = *ACPI_ADD_PTR(u8,
0503 &acpi_gbl_FADT,
0504 fadt_info_table[i].length);
0505
0506 name = fadt_info_table[i].name;
0507 flags = fadt_info_table[i].flags;
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537 if (address32) {
0538 if (address64->address) {
0539 if (address64->address != (u64)address32) {
0540
0541
0542
0543 ACPI_BIOS_WARNING((AE_INFO,
0544 "32/64X address mismatch in FADT/%s: "
0545 "0x%8.8X/0x%8.8X%8.8X, using %u-bit address",
0546 name, address32,
0547 ACPI_FORMAT_UINT64
0548 (address64->address),
0549 acpi_gbl_use32_bit_fadt_addresses
0550 ? 32 : 64));
0551 }
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561 if ((ACPI_MUL_8(length) <= ACPI_UINT8_MAX) &&
0562 (address64->bit_width !=
0563 ACPI_MUL_8(length))) {
0564 ACPI_BIOS_WARNING((AE_INFO,
0565 "32/64X length mismatch in FADT/%s: %u/%u",
0566 name,
0567 ACPI_MUL_8(length),
0568 address64->
0569 bit_width));
0570 }
0571 }
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583 if (!address64->address
0584 || acpi_gbl_use32_bit_fadt_addresses) {
0585 acpi_tb_init_generic_address(address64,
0586 ACPI_ADR_SPACE_SYSTEM_IO,
0587 length,
0588 (u64)address32,
0589 name, flags);
0590 }
0591 }
0592
0593 if (fadt_info_table[i].flags & ACPI_FADT_REQUIRED) {
0594
0595
0596
0597
0598 if (!address64->address || !length) {
0599 ACPI_BIOS_ERROR((AE_INFO,
0600 "Required FADT field %s has zero address and/or length: "
0601 "0x%8.8X%8.8X/0x%X",
0602 name,
0603 ACPI_FORMAT_UINT64(address64->
0604 address),
0605 length));
0606 }
0607 } else if (fadt_info_table[i].flags & ACPI_FADT_SEPARATE_LENGTH) {
0608
0609
0610
0611
0612
0613 if ((address64->address && !length) ||
0614 (!address64->address && length)) {
0615 ACPI_BIOS_WARNING((AE_INFO,
0616 "Optional FADT field %s has valid %s but zero %s: "
0617 "0x%8.8X%8.8X/0x%X", name,
0618 (length ? "Length" :
0619 "Address"),
0620 (length ? "Address" :
0621 "Length"),
0622 ACPI_FORMAT_UINT64
0623 (address64->address),
0624 length));
0625 }
0626 }
0627 }
0628 }
0629
0630
0631
0632
0633
0634
0635
0636
0637
0638
0639
0640
0641
0642
0643 static void acpi_tb_setup_fadt_registers(void)
0644 {
0645 struct acpi_generic_address *target64;
0646 struct acpi_generic_address *source64;
0647 u8 pm1_register_byte_width;
0648 u32 i;
0649
0650
0651
0652
0653
0654 if (acpi_gbl_use_default_register_widths) {
0655 for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
0656 target64 =
0657 ACPI_ADD_PTR(struct acpi_generic_address,
0658 &acpi_gbl_FADT,
0659 fadt_info_table[i].address64);
0660
0661
0662
0663
0664
0665 if ((target64->address) &&
0666 (fadt_info_table[i].default_length > 0) &&
0667 (fadt_info_table[i].default_length !=
0668 target64->bit_width)) {
0669 ACPI_BIOS_WARNING((AE_INFO,
0670 "Invalid length for FADT/%s: %u, using default %u",
0671 fadt_info_table[i].name,
0672 target64->bit_width,
0673 fadt_info_table[i].
0674 default_length));
0675
0676
0677
0678 target64->bit_width =
0679 fadt_info_table[i].default_length;
0680 }
0681 }
0682 }
0683
0684
0685
0686
0687
0688
0689 pm1_register_byte_width = (u8)
0690 ACPI_DIV_16(acpi_gbl_FADT.xpm1a_event_block.bit_width);
0691
0692
0693
0694
0695
0696
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706 for (i = 0; i < ACPI_FADT_PM_INFO_ENTRIES; i++) {
0707 source64 =
0708 ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
0709 fadt_pm_info_table[i].source);
0710
0711 if (source64->address) {
0712 acpi_tb_init_generic_address(fadt_pm_info_table[i].
0713 target, source64->space_id,
0714 pm1_register_byte_width,
0715 source64->address +
0716 (fadt_pm_info_table[i].
0717 register_num *
0718 pm1_register_byte_width),
0719 "PmRegisters", 0);
0720 }
0721 }
0722 }