All of lore.kernel.org
 help / color / mirror / Atom feed
From: Grzegorz Uriasz <gorbak25@gmail.com>
To: xen-devel@lists.xenproject.org
Cc: "Wei Liu" <wl@xen.org>,
	jakub@bartmin.ski, "Andrew Cooper" <andrew.cooper3@citrix.com>,
	marmarek@invisiblethingslab.com,
	"Grzegorz Uriasz" <gorbak25@gmail.com>,
	"Jan Beulich" <jbeulich@suse.com>,
	j.nowak26@student.uw.edu.pl, contact@puzio.waw.pl,
	"Roger Pau Monné" <roger.pau@citrix.com>
Subject: [PATCH v3 1/1] x86/acpi: Use FADT flags to determine the PMTMR width
Date: Fri, 19 Jun 2020 22:00:16 +0000	[thread overview]
Message-ID: <de0e33d2be0924e66a220678a7683098df70c2b5.1592603468.git.gorbak25@gmail.com> (raw)
In-Reply-To: <cover.1592603468.git.gorbak25@gmail.com>

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>
---
Cc: Jan Beulich <jbeulich@suse.com>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>
Cc: Wei Liu <wl@xen.org>
Cc: "Roger Pau Monné" <roger.pau@citrix.com>
Cc: marmarek@invisiblethingslab.com
Cc: contact@puzio.waw.pl
Cc: jakub@bartmin.ski
Cc: j.nowak26@student.uw.edu.pl

Changes in v2:
- Check pm timer access width
- Proper timer width is set when xpm block is not present
- Cleanup timer initialization

Changes in v3:
- Check pm timer bit offset
- Warn about acpi firmware bugs
- Drop int cast in init_pmtimer
- Merge if's in init_pmtimer
---
 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 bcba52e232..24fd236eb5 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 d643590c0a..8a45514908 100644
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -457,16 +457,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 = (1ull << pmtmr_width) - 1;
 
     count = inl(pmtmr_ioport) & mask;
     start = rdtsc_ordered();
@@ -486,7 +483,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.
-- 
2.27.0



  reply	other threads:[~2020-06-19 22:00 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-06-19 22:00 [PATCH v3 0/1] Fix broken suspend on some machines Grzegorz Uriasz
2020-06-19 22:00 ` Grzegorz Uriasz [this message]
2020-06-22  8:49   ` [PATCH v3 1/1] x86/acpi: Use FADT flags to determine the PMTMR width Jan Beulich
2020-06-24 15:31     ` Ping: " Jan Beulich
2020-06-25  6:55       ` Paul Durrant
2020-06-22  8:54   ` Roger Pau Monné
2020-06-22  8:58     ` Roger Pau Monné
2020-06-22 10:13     ` Jan Beulich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=de0e33d2be0924e66a220678a7683098df70c2b5.1592603468.git.gorbak25@gmail.com \
    --to=gorbak25@gmail.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=contact@puzio.waw.pl \
    --cc=j.nowak26@student.uw.edu.pl \
    --cc=jakub@bartmin.ski \
    --cc=jbeulich@suse.com \
    --cc=marmarek@invisiblethingslab.com \
    --cc=roger.pau@citrix.com \
    --cc=wl@xen.org \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.