Commit f06147f9 authored by Lv Zheng's avatar Lv Zheng Committed by Rafael J. Wysocki

ACPICA: Hardware: Enable firmware waking vector for both 32-bit and 64-bit FACS

ACPICA commit 368eb60778b27b6ae94d3658ddc902ca1342a963
ACPICA commit 70f62a80d65515e1285fdeeb50d94ee6f07df4bd
ACPICA commit a04dbfa308a48ab0b2d10519c54a6c533c5c8949
ACPICA commit ebd544ed24c5a4faba11f265e228b7a821a729f5

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 enables the firmware waking vectors for both 32bit/64bit FACS
tables in order to ensure we can exclude the cases that trigger the bugs
caused by the root cause 2. The exclusion is split into 2 commits so that
if it turns out not to be necessary, this single commit can be reverted
without affecting the useful one. Lv Zheng, Bob Moore.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=74021
Link: https://github.com/acpica/acpica/commit/368eb607
Link: https://github.com/acpica/acpica/commit/70f62a80
Link: https://github.com/acpica/acpica/commit/a04dbfa3
Link: https://github.com/acpica/acpica/commit/ebd544edReported-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>
parent c04e1fb4
...@@ -61,6 +61,8 @@ ACPI_GLOBAL(struct acpi_table_header, acpi_gbl_original_dsdt_header); ...@@ -61,6 +61,8 @@ ACPI_GLOBAL(struct acpi_table_header, acpi_gbl_original_dsdt_header);
#if (!ACPI_REDUCED_HARDWARE) #if (!ACPI_REDUCED_HARDWARE)
ACPI_GLOBAL(struct acpi_table_facs *, acpi_gbl_FACS); ACPI_GLOBAL(struct acpi_table_facs *, acpi_gbl_FACS);
ACPI_GLOBAL(struct acpi_table_facs *, acpi_gbl_facs32);
ACPI_GLOBAL(struct acpi_table_facs *, acpi_gbl_facs64);
#endif /* !ACPI_REDUCED_HARDWARE */ #endif /* !ACPI_REDUCED_HARDWARE */
......
...@@ -50,6 +50,13 @@ ...@@ -50,6 +50,13 @@
ACPI_MODULE_NAME("hwxfsleep") ACPI_MODULE_NAME("hwxfsleep")
/* Local prototypes */ /* Local prototypes */
#if (!ACPI_REDUCED_HARDWARE)
static acpi_status
acpi_hw_set_firmware_waking_vectors(struct acpi_table_facs *facs,
acpi_physical_address physical_address,
acpi_physical_address physical_address64);
#endif
static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id); static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id);
/* /*
...@@ -81,9 +88,10 @@ static struct acpi_sleep_functions acpi_sleep_dispatch[] = { ...@@ -81,9 +88,10 @@ static struct acpi_sleep_functions acpi_sleep_dispatch[] = {
#if (!ACPI_REDUCED_HARDWARE) #if (!ACPI_REDUCED_HARDWARE)
/******************************************************************************* /*******************************************************************************
* *
* FUNCTION: acpi_set_firmware_waking_vectors * FUNCTION: acpi_hw_set_firmware_waking_vectors
* *
* PARAMETERS: physical_address - 32-bit physical address of ACPI real mode * PARAMETERS: facs - Pointer to FACS table
* physical_address - 32-bit physical address of ACPI real mode
* entry point. * entry point.
* physical_address64 - 64-bit physical address of ACPI protected * physical_address64 - 64-bit physical address of ACPI protected
* mode entry point. * mode entry point.
...@@ -94,11 +102,12 @@ static struct acpi_sleep_functions acpi_sleep_dispatch[] = { ...@@ -94,11 +102,12 @@ static struct acpi_sleep_functions acpi_sleep_dispatch[] = {
* *
******************************************************************************/ ******************************************************************************/
acpi_status static acpi_status
acpi_set_firmware_waking_vectors(acpi_physical_address physical_address, acpi_hw_set_firmware_waking_vectors(struct acpi_table_facs *facs,
acpi_physical_address physical_address,
acpi_physical_address physical_address64) acpi_physical_address physical_address64)
{ {
ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vectors); ACPI_FUNCTION_TRACE(acpi_hw_set_firmware_waking_vectors);
/* /*
...@@ -111,20 +120,61 @@ acpi_set_firmware_waking_vectors(acpi_physical_address physical_address, ...@@ -111,20 +120,61 @@ acpi_set_firmware_waking_vectors(acpi_physical_address physical_address,
/* Set the 32-bit vector */ /* Set the 32-bit vector */
acpi_gbl_FACS->firmware_waking_vector = (u32)physical_address; facs->firmware_waking_vector = (u32)physical_address;
if (acpi_gbl_FACS->length > 32) { if (facs->length > 32) {
if (acpi_gbl_FACS->version >= 1) { if (facs->version >= 1) {
/* Set the 64-bit vector */ /* Set the 64-bit vector */
acpi_gbl_FACS->xfirmware_waking_vector = facs->xfirmware_waking_vector = physical_address64;
physical_address64;
} else { } else {
/* Clear the 64-bit vector if it exists */ /* Clear the 64-bit vector if it exists */
acpi_gbl_FACS->xfirmware_waking_vector = 0; facs->xfirmware_waking_vector = 0;
}
}
return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
*
* FUNCTION: acpi_set_firmware_waking_vectors
*
* PARAMETERS: physical_address - 32-bit physical address of ACPI real mode
* entry point.
* physical_address64 - 64-bit physical address of ACPI protected
* mode entry point.
*
* RETURN: Status
*
* DESCRIPTION: Sets the firmware_waking_vector fields of the FACS
*
******************************************************************************/
acpi_status
acpi_set_firmware_waking_vectors(acpi_physical_address physical_address,
acpi_physical_address physical_address64)
{
ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vectors);
/* If Hardware Reduced flag is set, there is no FACS */
if (acpi_gbl_reduced_hardware) {
return_ACPI_STATUS (AE_OK);
}
if (acpi_gbl_facs32) {
(void)acpi_hw_set_firmware_waking_vectors(acpi_gbl_facs32,
physical_address,
physical_address64);
} }
if (acpi_gbl_facs64) {
(void)acpi_hw_set_firmware_waking_vectors(acpi_gbl_facs64,
physical_address,
physical_address64);
} }
return_ACPI_STATUS(AE_OK); return_ACPI_STATUS(AE_OK);
......
...@@ -68,8 +68,6 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size); ...@@ -68,8 +68,6 @@ 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)
{ {
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 */
...@@ -81,18 +79,21 @@ acpi_status acpi_tb_initialize_facs(void) ...@@ -81,18 +79,21 @@ acpi_status acpi_tb_initialize_facs(void)
(void)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_CAST_INDIRECT_PTR(struct
acpi_table_header, acpi_table_header,
&facs32)); &acpi_gbl_facs32));
(void)acpi_get_table_by_index(ACPI_TABLE_INDEX_X_FACS, (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,
&facs64)); &acpi_gbl_facs64));
if (acpi_gbl_use32_bit_facs_addresses) { if (acpi_gbl_facs64
acpi_gbl_FACS = facs32 ? facs32 : facs64; && (!acpi_gbl_facs32 || !acpi_gbl_use32_bit_facs_addresses)) {
} else { acpi_gbl_FACS = acpi_gbl_facs64;
acpi_gbl_FACS = facs64 ? facs64 : facs32; } else if (acpi_gbl_facs32) {
acpi_gbl_FACS = acpi_gbl_facs32;
} }
/* If there is no FACS, just continue. There was already an error msg */
return (AE_OK); return (AE_OK);
} }
#endif /* !ACPI_REDUCED_HARDWARE */ #endif /* !ACPI_REDUCED_HARDWARE */
......
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