[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen stable-4.12] x86/acpi: use FADT flags to determine the PMTMR width



commit a1aae5418981fda97400400aeaab3d3a3c9e0297
Author:     Grzegorz Uriasz <gorbak25@xxxxxxxxx>
AuthorDate: Fri Aug 7 17:28:06 2020 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Fri Aug 7 17:28:06 2020 +0200

    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@xxxxxxxxx>
    Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>
    master commit: f325d2477eef8229c47d97031d314629521c70ab
    master date: 2020-06-25 09:11:09 +0200
---
 xen/arch/x86/acpi/boot.c    | 19 +++++++++++++++----
 xen/arch/x86/time.c         | 12 ++++--------
 xen/include/acpi/acmacros.h |  8 ++++++++
 3 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/xen/arch/x86/acpi/boot.c b/xen/arch/x86/acpi/boot.c
index e6ab9fa398..6398ee4b02 100644
--- a/xen/arch/x86/acpi/boot.c
+++ b/xen/arch/x86/acpi/boot.c
@@ -475,10 +475,17 @@ static int __init acpi_parse_fadt(struct 
acpi_table_header *table)
 
 #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;
                }
@@ -490,8 +497,12 @@ static int __init acpi_parse_fadt(struct acpi_table_header 
*table)
         */
        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);
diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c
index 02648915b1..8c5b9afdd6 100644
--- 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 __initdata plt_pmtimer =
     .name = "ACPI PM Timer",
     .frequency = ACPI_PM_FREQUENCY,
     .read_counter = read_pmtimer_count,
-    .counter_bits = 24,
     .init = init_pmtimer
 };
 
diff --git a/xen/include/acpi/acmacros.h b/xen/include/acpi/acmacros.h
index 6765535053..86c503c20f 100644
--- a/xen/include/acpi/acmacros.h
+++ b/xen/include/acpi/acmacros.h
@@ -121,6 +121,14 @@
 #define ACPI_COMPARE_NAME(a,b)          (!ACPI_STRNCMP (ACPI_CAST_PTR 
(char,(a)), ACPI_CAST_PTR (char,(b)), ACPI_NAME_SIZE))
 #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.
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.12



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.