Commit b078ec85 authored by Lv Zheng's avatar Lv Zheng Committed by Luis Henriques

ACPICA: Tables: Enable both 32-bit and 64-bit FACS

commit c04e1fb4 upstream.

ACPICA commit f7b86f35416e3d1f71c3d816ff5075ddd33ed486

The following commit is reported to have broken s2ram on some platforms:
 Commit: 0249ed24
 ACPICA: Add option to favor 32-bit FADT addresses.
The platform reports 2 FACS tables (which is not allowed by ACPI
specification) and the new 32-bit address favor rule forces OSPMs to use
the FACS table reported via FADT's X_FIRMWARE_CTRL field.

The root cause of the reported bug might be one of the followings:
1. BIOS may favor the 64-bit firmware waking vector address when the
   version of the FACS is greater than 0 and Linux currently only supports
   resuming from the real mode, so the 64-bit firmware waking vector has
   never been set and might be invalid to BIOS while the commit enables
   higher version FACS.
2. BIOS may favor the FACS reported via the "FIRMWARE_CTRL" field in the
   FADT while the commit doesn't set the firmware waking vector address of
   the FACS reported by "FIRMWARE_CTRL", it only sets the firware waking
   vector address of the FACS reported by "X_FIRMWARE_CTRL".

This patch excludes the cases that can trigger the bugs caused by the root
cause 2.

There is no handshaking mechanism can be used by OSPM to tell BIOS which
FACS is currently used. Thus the FACS reported by "FIRMWARE_CTRL" may still
be used by BIOS and the 0 value of the 32-bit firmware waking vector might
trigger such failure.

This patch tries to favor 32bit FACS address in another way where both the
FACS reported by "FIRMWARE_CTRL" and the FACS reported by "X_FIRMWARE_CTRL"
are loaded so that further commit can set firmware waking vector in the
both tables to ensure we can exclude the cases that trigger the bugs caused
by the root cause 2. The exclusion is split into 2 commits as this commit
is also useful for dumping more ACPI tables, it won't get reverted when
such exclusion is no longer necessary. Lv Zheng.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=74021
Link: https://github.com/acpica/acpica/commit/f7b86f35Reported-and-tested-by: default avatarOswald Buddenhagen <ossi@kde.org>
Signed-off-by: default avatarLv Zheng <lv.zheng@intel.com>
Signed-off-by: default avatarBob Moore <robert.moore@intel.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
parent 03ff028f
...@@ -213,6 +213,7 @@ struct acpi_table_list { ...@@ -213,6 +213,7 @@ struct acpi_table_list {
#define ACPI_TABLE_INDEX_DSDT (0) #define ACPI_TABLE_INDEX_DSDT (0)
#define ACPI_TABLE_INDEX_FACS (1) #define ACPI_TABLE_INDEX_FACS (1)
#define ACPI_TABLE_INDEX_X_FACS (2)
struct acpi_find_context { struct acpi_find_context {
char *search_for; char *search_for;
......
...@@ -350,10 +350,19 @@ void acpi_tb_parse_fadt(u32 table_index) ...@@ -350,10 +350,19 @@ void acpi_tb_parse_fadt(u32 table_index)
/* If Hardware Reduced flag is set, there is no FACS */ /* If Hardware Reduced flag is set, there is no FACS */
if (!acpi_gbl_reduced_hardware) { if (!acpi_gbl_reduced_hardware) {
if (acpi_gbl_FADT.facs) {
acpi_tb_install_fixed_table((acpi_physical_address) acpi_tb_install_fixed_table((acpi_physical_address)
acpi_gbl_FADT.Xfacs, ACPI_SIG_FACS, acpi_gbl_FADT.facs,
ACPI_SIG_FACS,
ACPI_TABLE_INDEX_FACS); ACPI_TABLE_INDEX_FACS);
} }
if (acpi_gbl_FADT.Xfacs) {
acpi_tb_install_fixed_table((acpi_physical_address)
acpi_gbl_FADT.Xfacs,
ACPI_SIG_FACS,
ACPI_TABLE_INDEX_X_FACS);
}
}
} }
/******************************************************************************* /*******************************************************************************
...@@ -491,13 +500,9 @@ static void acpi_tb_convert_fadt(void) ...@@ -491,13 +500,9 @@ static void acpi_tb_convert_fadt(void)
acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt); acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt);
/* /*
* Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary. * Expand the 32-bit DSDT addresses to 64-bit as necessary.
* Later ACPICA code will always use the X 64-bit field. * Later ACPICA code will always use the X 64-bit field.
*/ */
acpi_gbl_FADT.Xfacs = acpi_tb_select_address("FACS",
acpi_gbl_FADT.facs,
acpi_gbl_FADT.Xfacs);
acpi_gbl_FADT.Xdsdt = acpi_tb_select_address("DSDT", acpi_gbl_FADT.Xdsdt = acpi_tb_select_address("DSDT",
acpi_gbl_FADT.dsdt, acpi_gbl_FADT.dsdt,
acpi_gbl_FADT.Xdsdt); acpi_gbl_FADT.Xdsdt);
......
...@@ -68,7 +68,8 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size); ...@@ -68,7 +68,8 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size);
acpi_status acpi_tb_initialize_facs(void) acpi_status acpi_tb_initialize_facs(void)
{ {
acpi_status status; struct acpi_table_facs *facs32;
struct acpi_table_facs *facs64;
/* If Hardware Reduced flag is set, there is no FACS */ /* If Hardware Reduced flag is set, there is no FACS */
...@@ -77,11 +78,22 @@ acpi_status acpi_tb_initialize_facs(void) ...@@ -77,11 +78,22 @@ acpi_status acpi_tb_initialize_facs(void)
return (AE_OK); return (AE_OK);
} }
status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, (void)acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
ACPI_CAST_INDIRECT_PTR(struct
acpi_table_header,
&facs32));
(void)acpi_get_table_by_index(ACPI_TABLE_INDEX_X_FACS,
ACPI_CAST_INDIRECT_PTR(struct ACPI_CAST_INDIRECT_PTR(struct
acpi_table_header, acpi_table_header,
&acpi_gbl_FACS)); &facs64));
return (status);
if (acpi_gbl_use32_bit_facs_addresses) {
acpi_gbl_FACS = facs32 ? facs32 : facs64;
} else {
acpi_gbl_FACS = facs64 ? facs64 : facs32;
}
return (AE_OK);
} }
#endif /* !ACPI_REDUCED_HARDWARE */ #endif /* !ACPI_REDUCED_HARDWARE */
...@@ -101,7 +113,7 @@ acpi_status acpi_tb_initialize_facs(void) ...@@ -101,7 +113,7 @@ acpi_status acpi_tb_initialize_facs(void)
u8 acpi_tb_tables_loaded(void) u8 acpi_tb_tables_loaded(void)
{ {
if (acpi_gbl_root_table_list.current_table_count >= 3) { if (acpi_gbl_root_table_list.current_table_count >= 4) {
return (TRUE); return (TRUE);
} }
...@@ -357,11 +369,11 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) ...@@ -357,11 +369,11 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
table_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header)); table_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header));
/* /*
* First two entries in the table array are reserved for the DSDT * First three entries in the table array are reserved for the DSDT
* and FACS, which are not actually present in the RSDT/XSDT - they * and 32bit/64bit FACS, which are not actually present in the
* come from the FADT * RSDT/XSDT - they come from the FADT
*/ */
acpi_gbl_root_table_list.current_table_count = 2; acpi_gbl_root_table_list.current_table_count = 3;
/* Initialize the root table array from the RSDT/XSDT */ /* Initialize the root table array from the RSDT/XSDT */
......
...@@ -166,7 +166,8 @@ static acpi_status acpi_tb_load_namespace(void) ...@@ -166,7 +166,8 @@ static acpi_status acpi_tb_load_namespace(void)
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) {
if ((!ACPI_COMPARE_NAME if (!acpi_gbl_root_table_list.tables[i].address ||
(!ACPI_COMPARE_NAME
(&(acpi_gbl_root_table_list.tables[i].signature), (&(acpi_gbl_root_table_list.tables[i].signature),
ACPI_SIG_SSDT) ACPI_SIG_SSDT)
&& &&
......
...@@ -201,6 +201,15 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_do_not_use_xsdt, FALSE); ...@@ -201,6 +201,15 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_do_not_use_xsdt, FALSE);
*/ */
ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_fadt_addresses, TRUE); ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_fadt_addresses, TRUE);
/*
* Optionally use 32-bit FACS table addresses.
* It is reported that some platforms fail to resume from system suspending
* if 64-bit FACS table address is selected:
* https://bugzilla.kernel.org/show_bug.cgi?id=74021
* Default is TRUE, favor the 32-bit addresses.
*/
ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_facs_addresses, TRUE);
/* /*
* Optionally truncate I/O addresses to 16 bits. Provides compatibility * Optionally truncate I/O addresses to 16 bits. Provides compatibility
* with other ACPI implementations. NOTE: During ACPICA initialization, * with other ACPI implementations. NOTE: During ACPICA initialization,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment