diff options
Diffstat (limited to '5ef44e0d-x86-PMTMR-use-FADT-flags.patch')
| -rw-r--r-- | 5ef44e0d-x86-PMTMR-use-FADT-flags.patch | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/5ef44e0d-x86-PMTMR-use-FADT-flags.patch b/5ef44e0d-x86-PMTMR-use-FADT-flags.patch new file mode 100644 index 0000000..916fd44 --- /dev/null +++ b/5ef44e0d-x86-PMTMR-use-FADT-flags.patch @@ -0,0 +1,102 @@ +# Commit f325d2477eef8229c47d97031d314629521c70ab +# Date 2020-06-25 09:11:09 +0200 +# Author Grzegorz Uriasz <gorbak25@gmail.com> +# Committer Jan Beulich <jbeulich@suse.com> +x86/acpi: use FADT flags to determine the PMTMR width + +On some computers the bit width of the PM Timer as reported +by ACPI is 32 bits when in fact the FADT flags report correctly +that the timer is 24 bits wide. On affected machines such as the +ASUS FX504GM and never gaming laptops this results in the inability +to resume the machine from suspend. Without this patch suspend is +broken on affected machines and even if a machine manages to resume +correctly then the kernel time and xen timers are trashed. + +Signed-off-by: Grzegorz Uriasz <gorbak25@gmail.com> +Reviewed-by: Jan Beulich <jbeulich@suse.com> + +--- a/xen/arch/x86/acpi/boot.c ++++ b/xen/arch/x86/acpi/boot.c +@@ -473,10 +473,17 @@ static int __init acpi_parse_fadt(struct + + #ifdef CONFIG_X86_PM_TIMER + /* detect the location of the ACPI PM Timer */ +- if (fadt->header.revision >= FADT2_REVISION_ID) { ++ if (fadt->header.revision >= FADT2_REVISION_ID && ++ fadt->xpm_timer_block.space_id == ACPI_ADR_SPACE_SYSTEM_IO) { + /* FADT rev. 2 */ +- if (fadt->xpm_timer_block.space_id == +- ACPI_ADR_SPACE_SYSTEM_IO) { ++ if (fadt->xpm_timer_block.access_width != 0 && ++ ACPI_ACCESS_BIT_WIDTH(fadt->xpm_timer_block.access_width) != 32) ++ printk(KERN_WARNING PREFIX "PM-Timer has invalid access width(%u)\n", ++ fadt->xpm_timer_block.access_width); ++ else if (fadt->xpm_timer_block.bit_offset != 0) ++ printk(KERN_WARNING PREFIX "PM-Timer has invalid bit offset(%u)\n", ++ fadt->xpm_timer_block.bit_offset); ++ else { + pmtmr_ioport = fadt->xpm_timer_block.address; + pmtmr_width = fadt->xpm_timer_block.bit_width; + } +@@ -488,8 +495,12 @@ static int __init acpi_parse_fadt(struct + */ + if (!pmtmr_ioport) { + pmtmr_ioport = fadt->pm_timer_block; +- pmtmr_width = fadt->pm_timer_length == 4 ? 24 : 0; ++ pmtmr_width = fadt->pm_timer_length == 4 ? 32 : 0; + } ++ if (pmtmr_width < 32 && (fadt->flags & ACPI_FADT_32BIT_TIMER)) ++ printk(KERN_WARNING PREFIX "PM-Timer is too short\n"); ++ if (pmtmr_width > 24 && !(fadt->flags & ACPI_FADT_32BIT_TIMER)) ++ pmtmr_width = 24; + if (pmtmr_ioport) + printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x (%u bits)\n", + pmtmr_ioport, pmtmr_width); +--- a/xen/arch/x86/time.c ++++ b/xen/arch/x86/time.c +@@ -452,16 +452,13 @@ static u64 read_pmtimer_count(void) + static s64 __init init_pmtimer(struct platform_timesource *pts) + { + u64 start; +- u32 count, target, mask = 0xffffff; ++ u32 count, target, mask; + +- if ( !pmtmr_ioport || !pmtmr_width ) ++ if ( !pmtmr_ioport || (pmtmr_width != 24 && pmtmr_width != 32) ) + return 0; + +- if ( pmtmr_width == 32 ) +- { +- pts->counter_bits = 32; +- mask = 0xffffffff; +- } ++ pts->counter_bits = pmtmr_width; ++ mask = 0xffffffff >> (32 - pmtmr_width); + + count = inl(pmtmr_ioport) & mask; + start = rdtsc_ordered(); +@@ -481,7 +478,6 @@ static struct platform_timesource __init + .name = "ACPI PM Timer", + .frequency = ACPI_PM_FREQUENCY, + .read_counter = read_pmtimer_count, +- .counter_bits = 24, + .init = init_pmtimer + }; + +--- a/xen/include/acpi/acmacros.h ++++ b/xen/include/acpi/acmacros.h +@@ -122,6 +122,14 @@ + #endif + + /* ++ * Algorithm to obtain access bit or byte width. ++ * Can be used with access_width of struct acpi_generic_address and access_size of ++ * struct acpi_resource_generic_register. ++ */ ++#define ACPI_ACCESS_BIT_WIDTH(size) (1 << ((size) + 2)) ++#define ACPI_ACCESS_BYTE_WIDTH(size) (1 << ((size) - 1)) ++ ++/* + * Macros for moving data around to/from buffers that are possibly unaligned. + * If the hardware supports the transfer of unaligned data, just do the store. + * Otherwise, we have to move one byte at a time. |
