From patchwork Wed Jun 16 05:57:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AceLan Kao X-Patchwork-Id: 1492719 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=jx3v2cRv; dkim-atps=neutral Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4G4ZHG716Lz9sXG; Wed, 16 Jun 2021 15:58:18 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1ltOZ3-00060H-UY; Wed, 16 Jun 2021 05:58:13 +0000 Received: from mail-pg1-f173.google.com ([209.85.215.173]) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1ltOYx-0005oj-UG for kernel-team@lists.ubuntu.com; Wed, 16 Jun 2021 05:58:08 +0000 Received: by mail-pg1-f173.google.com with SMTP id i34so1065680pgl.9 for ; Tue, 15 Jun 2021 22:57:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=afWmAmAAPfktAz9CXWsVsMIqITjwoOPZgUlc3vs2+to=; b=jx3v2cRvW6l7nYgRSvRwvB8x220NuInBj6UjYIeLwr1onn9zAA8UIQ/diL/njIe9fF zEid3738gMjE28LuMadB1NcQwrtFPtsEk13XOfKS69siwWHCXzDbPuNHrLJZNnhy8Tn5 agqIXfi9Koub5WYjTXN7cmOXNt7kB1XqTikQlduZkaN8T14uXaR60TDBOYgwby/XMlTr //0r7mvf/s0uhbBpQvZY25y9HNRea20+z6Lk+BRZGUwHu4JtARbWpzZBt7HaNlZG5vUO O3TWvvdtNvDVFn1wbr2onuoAXISXsNd2xqCQMJkwncwqcbEcX4osDTT0MMc5H7vEjNag gt+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=afWmAmAAPfktAz9CXWsVsMIqITjwoOPZgUlc3vs2+to=; b=VrPLFaBS6g13YpRpkHosukO/zVn7hxUwHNIp9rtF50qZ81sn3bn7mxPzV192b5mBTN 5zYb7co8eRHOuvCMKsRQx2hp4QD/4PTYfz4EIYYfCDupr9692haUI4HxjLxC8xgwEYh3 ATLeTVzAHd5HH3H9FhW3+owSTWimbfl/CpsNT8SYpYT+yhxCe/qQ37t72p/eC7ldp8Qw vvaQ5svwcIPdTVmxkQL9ySgU0cJdWyjjnk/udWzGgJ4Cg3GNPtnJe7x2zUapjBUrxljj YFahMirG6eL5IUoEYwwzWHhX2nMd5GAh4/h+jZsPsy8zA4QTLlDOKJMJLfGkqZ1+zoui HjlA== X-Gm-Message-State: AOAM533ssyMmdAduCEhZHVGpT/ME1rsrMIAh6Pk91J910eJSWFBuGR0m 6y1lpknpHuqaihtkF12HVZHvJjy50NM= X-Google-Smtp-Source: ABdhPJwcpJeddH8X5cb0xAfJBX751nUryv3Wh1+5yeGDClGEwazRSL9ZP+oP8GDqBIWyBM92BFjrHA== X-Received: by 2002:aa7:83d9:0:b029:2eb:b0ef:2a67 with SMTP id j25-20020aa783d90000b02902ebb0ef2a67mr8072249pfn.1.1623823073261; Tue, 15 Jun 2021 22:57:53 -0700 (PDT) Received: from localhost (61-220-137-34.HINET-IP.hinet.net. [61.220.137.34]) by smtp.gmail.com with ESMTPSA id x4sm890858pfc.150.2021.06.15.22.57.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 15 Jun 2021 22:57:52 -0700 (PDT) From: AceLan Kao To: kernel-team@lists.ubuntu.com, Kunyang_Fan Subject: [RESEND][PATCH 3/6][SRU][Unstable] UBUNTU: ODM: watchdog: add driver for AAEON devices Date: Wed, 16 Jun 2021 13:57:00 +0800 Message-Id: <20210616055703.124039-16-acelan.kao@canonical.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210616055703.124039-1-acelan.kao@canonical.com> References: <20210616055703.124039-1-acelan.kao@canonical.com> MIME-Version: 1.0 Received-SPF: pass client-ip=209.85.215.173; envelope-from=acelan@gmail.com; helo=mail-pg1-f173.google.com X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Kunyang_Fan BugLink: https://bugs.launchpad.net/bugs/1929504 This patch adds support for the watchdog whose control are transported to BIOS through ASUS WMI interface. This driver imitates the old type SIO watchdog driver to provide the basic control for watchdog functions. Signed-off-by: Kunyang_Fan Review-by: Kai-Heng Feng Review-by: Chia-Lin Kao (AceLan) Signed-off-by: Chia-Lin Kao (AceLan) --- drivers/watchdog/Kconfig | 13 ++ drivers/watchdog/Makefile | 1 + drivers/watchdog/wdt_aaeon.c | 242 +++++++++++++++++++++++++++++++++++ 3 files changed, 256 insertions(+) create mode 100644 drivers/watchdog/wdt_aaeon.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 355100dad60a..364c3deacd18 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1588,6 +1588,19 @@ config NIC7018_WDT To compile this driver as a module, choose M here: the module will be called nic7018_wdt. +config AAEON_IWMI_WDT + tristate "AAEON Watchdog Timer" + depends on ASUS_WMI + depends on UBUNTU_ODM_DRIVERS + select MFD_AAEON + help + This is the driver for the hardware watchdog on Single Board + Computers produced by AAEON.Say `Y' here to support its built-in + watchdog timer feature. + + This driver leverages the ASUS WMI interface to access device + resources. + # M68K Architecture config M54xx_WATCHDOG diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index a7eade8b4d45..094ebc9294a4 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -142,6 +142,7 @@ obj-$(CONFIG_NI903X_WDT) += ni903x_wdt.o obj-$(CONFIG_NIC7018_WDT) += nic7018_wdt.o obj-$(CONFIG_MLX_WDT) += mlx_wdt.o obj-$(CONFIG_KEEMBAY_WATCHDOG) += keembay_wdt.o +obj-$(CONFIG_AAEON_IWMI_WDT) += wdt_aaeon.o # M68K Architecture obj-$(CONFIG_M54xx_WATCHDOG) += m54xx_wdt.o diff --git a/drivers/watchdog/wdt_aaeon.c b/drivers/watchdog/wdt_aaeon.c new file mode 100644 index 000000000000..41c68805cc93 --- /dev/null +++ b/drivers/watchdog/wdt_aaeon.c @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AAEON WDT driver + * + * Author: Edward Lin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AAEON_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66" +#define WMI_WDT_GETMAX_METHOD_ID 0x00020000 +#define WMI_WDT_GETVALUE_METHOD_ID 0x00020001 +#define WMI_WDT_SETANDSTOP_METHOD_ID 0x00020002 + +#define WMI_WDT_SUPPORTED_DEVICE_ID \ + 0x12 /* Dev_Id for WDT_WMI supported or not */ +#define WMI_WDT_GETMAX_DEVICE_ID 0x10 /* Dev_Id for WDT_WMI get Max timeout */ +#define WMI_WDT_STOP_DEVICE_ID 0x00 /* Dev_Id for WDT_WMI stop watchdog*/ + +/* Default values */ +#define WATCHDOG_TIMEOUT 60000 /* 1 minute default timeout */ +#define WATCHDOG_MAX_TIMEOUT (60000 * 255) /* WD_TIME is a byte long */ +#define WATCHDOG_PULSE_WIDTH 5000 /* default pulse width for watchdog signal */ + +static const int max_timeout = WATCHDOG_MAX_TIMEOUT; +static int timeout = WATCHDOG_TIMEOUT; /* default timeout in seconds */ +module_param(timeout, int, 0); +MODULE_PARM_DESC(timeout, "Initial watchdog timeout in mini-seconds"); + +static bool nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, bool, 0444); +MODULE_PARM_DESC(nowayout, " Disable watchdog shutdown on close"); + +/* Wdog internal data information */ +struct watchdog_data { + unsigned long opened; /* driver open state */ + struct mutex lock; /* concurrency control */ + char expect_close; /* controlled close */ + struct watchdog_info ident; /* wdog information*/ + unsigned short timeout; /* current wdog timeout */ + u8 timer_val; /* content for the WD_TIME register */ + char minutes_mode; + u8 pulse_val; /* pulse width flag */ + char pulse_mode; /* enable pulse output mode? */ + char caused_reboot;/* last reboot was by the watchdog */ +}; + +static long aaeon_watchdog_ioctl(struct file *file, unsigned int cmd, + unsigned long arg); +static int aaeon_watchdog_notify_sys(struct notifier_block *this, + unsigned long code, void *unused); + +static struct watchdog_data watchdog = { + .lock = __MUTEX_INITIALIZER(watchdog.lock), +}; + +/* /dev/watchdog api available options */ +static const struct file_operations watchdog_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = aaeon_watchdog_ioctl, +}; + +static struct miscdevice watchdog_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &watchdog_fops, +}; + +static struct notifier_block watchdog_notifier = { + .notifier_call = aaeon_watchdog_notify_sys, +}; + +/* Internal Configuration functions */ +static int aaeon_watchdog_set_timeout(int timeout) +{ + int err = 0; + u32 retval, dev_id = timeout; + + if (timeout <= 0 || timeout > max_timeout) { + pr_debug("watchdog timeout out of range\n"); + return -EINVAL; + } + + mutex_lock(&watchdog.lock); + err = asus_wmi_evaluate_method(WMI_WDT_SETANDSTOP_METHOD_ID, + dev_id, 0, &retval); + mutex_unlock(&watchdog.lock); + + return err; +} + +static int aaeon_watchdog_get_timeout(void) +{ + int err = 0; + u32 retval; + + if (timeout <= 0 || timeout > max_timeout) { + pr_debug("watchdog timeout out of range\n"); + return -EINVAL; + } + mutex_lock(&watchdog.lock); + err = asus_wmi_evaluate_method(WMI_WDT_GETVALUE_METHOD_ID, + 0, 0, &retval); + mutex_unlock(&watchdog.lock); + + return err ? err : retval; +} + +static int aaeon_watchdog_stop(void) +{ + int err = 0; + + mutex_lock(&watchdog.lock); + err = asus_wmi_evaluate_method(WMI_WDT_SETANDSTOP_METHOD_ID, + 0, 0, NULL); + mutex_unlock(&watchdog.lock); + + return err; +} + +static int aaeon_watchdog_get_maxsupport(void) +{ + int err; + u32 retval; + + mutex_lock(&watchdog.lock); + err = asus_wmi_evaluate_method(WMI_WDT_GETMAX_METHOD_ID, + WMI_WDT_GETMAX_DEVICE_ID, + 0, &retval); + mutex_unlock(&watchdog.lock); + + return err ? err : retval; + +} + +static long aaeon_watchdog_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int new_timeout; + + union { + struct watchdog_info __user *ident; + int __user *i; + } uarg; + + uarg.i = (int __user *) arg; + switch (cmd) { + case WDIOC_SETTIMEOUT: + if (get_user(new_timeout, uarg.i)) + return -EFAULT; + if (aaeon_watchdog_set_timeout(new_timeout)) + return -EINVAL; + return 0; + case WDIOC_GETTIMEOUT: + return aaeon_watchdog_get_timeout(); + case WDIOS_DISABLECARD: + return aaeon_watchdog_stop(); + case WDIOC_GETSUPPORT: + return aaeon_watchdog_get_maxsupport(); + default: + return -ENOTTY; + } +} + +static int aaeon_watchdog_notify_sys(struct notifier_block *this, + unsigned long code, void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) + aaeon_watchdog_stop(); + return NOTIFY_DONE; +} + +static int aaeon_wdt_probe(struct platform_device *pdev) +{ + int err = 0; + int retval = 0; + + pr_debug("aaeon watchdog device probe!\n"); + if (!wmi_has_guid(AAEON_WMI_MGMT_GUID)) { + pr_debug("AAEON Management GUID not found\n"); + return -ENODEV; + } + err = asus_wmi_evaluate_method(WMI_WDT_GETMAX_METHOD_ID, + WMI_WDT_SUPPORTED_DEVICE_ID, 0, &retval); + if (err) + goto exit; + + /* + * This driver imitates the old type SIO watchdog driver to + * provide the basic control for watchdog functions and only + * access by customized userspace tool + */ + err = misc_register(&watchdog_miscdev); + if (err) { + pr_debug(" cannot register miscdev on minor=%d\n", + watchdog_miscdev.minor); + goto exit; + } + + err = register_reboot_notifier(&watchdog_notifier); + if (err) + goto exit_miscdev; + + if (nowayout) + __module_get(THIS_MODULE); + + return 0; + +exit_miscdev: + misc_deregister(&watchdog_miscdev); +exit: + return err; +} + +static struct platform_driver aaeon_wdt_driver = { + .driver = { + .name = "wdt-aaeon", + }, +}; + +module_platform_driver_probe(aaeon_wdt_driver, aaeon_wdt_probe); + +MODULE_ALIAS("platform:wdt-aaeon"); +MODULE_DESCRIPTION("AAEON WDT Driver"); +MODULE_AUTHOR("Edward Lin "); +MODULE_LICENSE("GPL v2");