126 lines
3.8 KiB
Diff
126 lines
3.8 KiB
Diff
|
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
|
||
|
|