summaryrefslogtreecommitdiff
path: root/5ef44e0d-x86-PMTMR-use-FADT-flags.patch
diff options
context:
space:
mode:
Diffstat (limited to '5ef44e0d-x86-PMTMR-use-FADT-flags.patch')
-rw-r--r--5ef44e0d-x86-PMTMR-use-FADT-flags.patch102
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.