aboutsummarylogtreecommitdiffstats
path: root/0002-ACPI-watchdog-Prefer-iTCO_wdt-on-Lenovo-Z50-70.patch
diff options
context:
space:
mode:
Diffstat (limited to '0002-ACPI-watchdog-Prefer-iTCO_wdt-on-Lenovo-Z50-70.patch')
-rw-r--r--0002-ACPI-watchdog-Prefer-iTCO_wdt-on-Lenovo-Z50-70.patch125
1 files changed, 125 insertions, 0 deletions
diff --git a/0002-ACPI-watchdog-Prefer-iTCO_wdt-on-Lenovo-Z50-70.patch b/0002-ACPI-watchdog-Prefer-iTCO_wdt-on-Lenovo-Z50-70.patch
new file mode 100644
index 000000000000..ecd2d721d1c1
--- /dev/null
+++ b/0002-ACPI-watchdog-Prefer-iTCO_wdt-on-Lenovo-Z50-70.patch
@@ -0,0 +1,125 @@
+From f593e0bde601ff2b4f84b7363e4dfcbbda652e6d Mon Sep 17 00:00:00 2001
+Message-Id: <f593e0bde601ff2b4f84b7363e4dfcbbda652e6d.1527290717.git.jan.steffens@gmail.com>
+In-Reply-To: <ee91df95bf010fad44be5d2564e7d40038987f19.1527290717.git.jan.steffens@gmail.com>
+References: <ee91df95bf010fad44be5d2564e7d40038987f19.1527290717.git.jan.steffens@gmail.com>
+From: Mika Westerberg <mika.westerberg@linux.intel.com>
+Date: Mon, 23 Apr 2018 14:16:03 +0300
+Subject: [PATCH 2/3] ACPI / watchdog: Prefer iTCO_wdt on Lenovo Z50-70
+
+WDAT table on Lenovo Z50-70 is using RTC SRAM (ports 0x70 and 0x71) to
+store state of the timer. This conflicts with Linux RTC driver
+(rtc-cmos.c) who fails to reserve those ports for itself preventing RTC
+from functioning. In addition the WDAT table seems not to be fully
+functional because it does not reset the system when the watchdog times
+out.
+
+On this system iTCO_wdt works just fine so we simply prefer to use it
+instead of WDAT. This makes RTC working again and also results working
+watchdog via iTCO_wdt.
+
+Reported-by: Peter Milley <pbmilley@gmail.com>
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=199033
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+---
+ drivers/acpi/acpi_watchdog.c | 59 ++++++++++++++++++++++++++++++------
+ 1 file changed, 49 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/acpi/acpi_watchdog.c b/drivers/acpi/acpi_watchdog.c
+index ebb626ffb5fa..4bde16fb97d8 100644
+--- a/drivers/acpi/acpi_watchdog.c
++++ b/drivers/acpi/acpi_watchdog.c
+@@ -12,41 +12,80 @@
+ #define pr_fmt(fmt) "ACPI: watchdog: " fmt
+
+ #include <linux/acpi.h>
++#include <linux/dmi.h>
+ #include <linux/ioport.h>
+ #include <linux/platform_device.h>
+
+ #include "internal.h"
+
++static const struct dmi_system_id acpi_watchdog_skip[] = {
++ {
++ /*
++ * On Lenovo Z50-70 there are two issues with the WDAT
++ * table. First some of the instructions use RTC SRAM
++ * to store persistent information. This does not work well
++ * with Linux RTC driver. Second, more important thing is
++ * that the instructions do not actually reset the system.
++ *
++ * On this particular system iTCO_wdt seems to work just
++ * fine so we prefer that over WDAT for now.
++ *
++ * See also https://bugzilla.kernel.org/show_bug.cgi?id=199033.
++ */
++ .ident = "Lenovo Z50-70",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "20354"),
++ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Z50-70"),
++ },
++ },
++ {}
++};
++
++static const struct acpi_table_wdat *acpi_watchdog_get_wdat(void)
++{
++ const struct acpi_table_wdat *wdat = NULL;
++ acpi_status status;
++
++ if (acpi_disabled)
++ return NULL;
++
++ if (dmi_check_system(acpi_watchdog_skip))
++ return NULL;
++
++ status = acpi_get_table(ACPI_SIG_WDAT, 0,
++ (struct acpi_table_header **)&wdat);
++ if (ACPI_FAILURE(status)) {
++ /* It is fine if there is no WDAT */
++ return NULL;
++ }
++
++ return wdat;
++}
++
+ /**
+ * Returns true if this system should prefer ACPI based watchdog instead of
+ * the native one (which are typically the same hardware).
+ */
+ bool acpi_has_watchdog(void)
+ {
+- struct acpi_table_header hdr;
+-
+- if (acpi_disabled)
+- return false;
+-
+- return ACPI_SUCCESS(acpi_get_table_header(ACPI_SIG_WDAT, 0, &hdr));
++ return !!acpi_watchdog_get_wdat();
+ }
+ EXPORT_SYMBOL_GPL(acpi_has_watchdog);
+
+ void __init acpi_watchdog_init(void)
+ {
+ const struct acpi_wdat_entry *entries;
+ const struct acpi_table_wdat *wdat;
+ struct list_head resource_list;
+ struct resource_entry *rentry;
+ struct platform_device *pdev;
+ struct resource *resources;
+ size_t nresources = 0;
+- acpi_status status;
+ int i;
+
+- status = acpi_get_table(ACPI_SIG_WDAT, 0,
+- (struct acpi_table_header **)&wdat);
+- if (ACPI_FAILURE(status)) {
++ wdat = acpi_watchdog_get_wdat();
++ if (!wdat) {
+ /* It is fine if there is no WDAT */
+ return;
+ }
+--
+2.17.0
+