From patchwork Thu Aug 1 20:58:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Balantzyan X-Patchwork-Id: 11071359 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A70A3746 for ; Thu, 1 Aug 2019 20:58:42 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8E2C8285B7 for ; Thu, 1 Aug 2019 20:58:42 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 82376286BE; Thu, 1 Aug 2019 20:58:42 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A7796285B7 for ; Thu, 1 Aug 2019 20:58:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732856AbfHAU6l (ORCPT ); Thu, 1 Aug 2019 16:58:41 -0400 Received: from mail-pf1-f196.google.com ([209.85.210.196]:41046 "EHLO mail-pf1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728669AbfHAU6k (ORCPT ); Thu, 1 Aug 2019 16:58:40 -0400 Received: by mail-pf1-f196.google.com with SMTP id m30so34763675pff.8; Thu, 01 Aug 2019 13:58:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=WYyR2bYXed0QuZdNZYwYmS0w5vYhoD2p09J36Ydsq50=; b=jhB9RSk22TPYT4M9ZlhGdQaxoLrL0udQkPMD3LHK3Yx4Z0SOzM25PJHJOc5sElJFH7 v9TZ3yYMqRrIgrfG/bhsoNwItZbKv8gEe5D+VOENWVuVccLX4ke7Co9u2kFDzGId5/cr TyHmIYPE/5pao8ujZFq8+3tzUSvu/II3fexODlc09Icn4VEVVThD2a/0QuNhE9LcNAAN xSuiqLJ6T+ZW8VrImzTjUcCF7oiSYKA1JzrGxBTnDwzcEFKIzXkOaSP9W2JpEbONx9kt jerDL1flDhSIw6ho/W4uDq3jyVMFNjeewduAMootjNwUA/KxrMDOIvtGsDmH007WmTo6 wpGA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=WYyR2bYXed0QuZdNZYwYmS0w5vYhoD2p09J36Ydsq50=; b=fovYuIBI1ic8FrRj5AGYTlQBdeVnnVtnPQdiOUzAHvsijt9uxX6h3TsoF842xYFxOC gL2K9Y5S/gr/gHZsxD/85fT/62IZ5Z2efbd9ZHBXJaUKi0zcQMl05ZMAf8ou1LD7WCc7 c+txuUs8qJB/ATO5tYPI/fxAEPV/EUDLlgP4Uih4R/k068ld9cafHuBufJ79pNI34JK1 3ujxhsto/niB19ucXmx7aKUsKJETCxuGTK1iMg+IORyt2QicfWjcwktLGa4a4H3Ni75T GhLE8iRPd8x6byziS/++YI+6J6j0s6cmG61UVsIE1YGWjsts6aMo2V4JiQx0ZMN/ocdN I22A== X-Gm-Message-State: APjAAAXPGfO3ulJvzDgIaZPHYKoLUd7ym5DP9kIcFxFVZgwfYJF8Df+y pzWwMiuLWUVHqRoxz5S59fM= X-Google-Smtp-Source: APXvYqw5OgpFbbuBcgL2UAti1/+kdi3Y7D2OmvheNUdXDf7B2+srqxBVbsiGftQxSYg5VjV6KBtU0w== X-Received: by 2002:a17:90a:9b08:: with SMTP id f8mr705288pjp.103.1564693119732; Thu, 01 Aug 2019 13:58:39 -0700 (PDT) Received: from localhost.localdomain (d206-116-172-62.bchsia.telus.net. [206.116.172.62]) by smtp.gmail.com with ESMTPSA id b16sm117971113pfo.54.2019.08.01.13.58.38 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Thu, 01 Aug 2019 13:58:39 -0700 (PDT) From: Mark Balantzyan To: linux@roeck-us.net Cc: mbalant3@gmail.com, wim@linux-watchdog.org, linux-kernel@vger.kernel.org, linux-watchdog@vger.kernel.org Subject: [PATCH v2] watchdog: alim1535: Rewriting of alim1535 to use watchdog subsystem Date: Thu, 1 Aug 2019 13:58:34 -0700 Message-Id: <20190801205834.20956-1-mbalant3@gmail.com> X-Mailer: git-send-email 2.17.1 Sender: linux-watchdog-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-watchdog@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch rewrites the alim1535_wdt driver to use the watchdog subsystem. By virtue of this, it also fixes a potential race condition between ali_timeout_bits and ali_settimer(). Signed-off-by: Mark Balantzyan --- drivers/watchdog/Kconfig | 1 + drivers/watchdog/alim1535_wdt.c | 275 +++++--------------------------- 2 files changed, 37 insertions(+), 239 deletions(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 9af07fd9..980b0c90 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -853,6 +853,7 @@ config ADVANTECH_WDT config ALIM1535_WDT tristate "ALi M1535 PMU Watchdog Timer" + select WATCHDOG_CORE depends on X86 && PCI ---help--- This is the driver for the hardware watchdog on the ALi M1535 PMU. diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c index 60f0c2eb..55648ba8 100644 --- a/drivers/watchdog/alim1535_wdt.c +++ b/drivers/watchdog/alim1535_wdt.c @@ -12,26 +12,18 @@ #include #include #include -#include #include #include -#include -#include -#include -#include -#include #include #include +#include #define WATCHDOG_NAME "ALi_M1535" #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ /* internal variables */ -static unsigned long ali_is_open; -static char ali_expect_release; static struct pci_dev *ali_pci; static u32 ali_timeout_bits; /* stores the computed timeout */ -static DEFINE_SPINLOCK(ali_lock); /* Guards the hardware */ /* module parameters */ static int timeout = WATCHDOG_TIMEOUT; @@ -53,18 +45,15 @@ MODULE_PARM_DESC(nowayout, * configuration set. */ -static void ali_start(void) +static int ali_start(struct watchdog_device *wdd) { u32 val; - spin_lock(&ali_lock); - pci_read_config_dword(ali_pci, 0xCC, &val); val &= ~0x3F; /* Mask count */ val |= (1 << 25) | ali_timeout_bits; pci_write_config_dword(ali_pci, 0xCC, val); - - spin_unlock(&ali_lock); + return 0; } /* @@ -73,18 +62,15 @@ static void ali_start(void) * Stop the ALi watchdog countdown */ -static void ali_stop(void) +static int ali_stop(struct watchdog_device *wdd) { u32 val; - spin_lock(&ali_lock); - pci_read_config_dword(ali_pci, 0xCC, &val); val &= ~0x3F; /* Mask count to zero (disabled) */ val &= ~(1 << 25); /* and for safety mask the reset enable */ pci_write_config_dword(ali_pci, 0xCC, val); - - spin_unlock(&ali_lock); + return 0; } /* @@ -93,32 +79,24 @@ static void ali_stop(void) * Send a keepalive to the timer (actually we restart the timer). */ -static void ali_keepalive(void) +static int ali_keepalive(struct watchdog_device *wdd) { - ali_start(); + ali_start(wdd); + return 0; } /* - * ali_settimer - compute the timer reload value + * ali_set_timeout - compute the timer reload value * @t: time in seconds * * Computes the timeout values needed */ -static int ali_settimer(int t) +static int ali_set_timeout(struct watchdog_device *wdd, unsigned int t) { - if (t < 0) - return -EINVAL; - else if (t < 60) - ali_timeout_bits = t|(1 << 6); - else if (t < 3600) - ali_timeout_bits = (t / 60)|(1 << 7); - else if (t < 18000) - ali_timeout_bits = (t / 300)|(1 << 6)|(1 << 7); - else - return -EINVAL; - - timeout = t; + wdd->max_timeout = 60; + wdd->min_timeout = 1; + wdd->timeout = t; return 0; } @@ -126,172 +104,6 @@ static int ali_settimer(int t) * /dev/watchdog handling */ -/* - * ali_write - writes to ALi watchdog - * @file: file from VFS - * @data: user address of data - * @len: length of data - * @ppos: pointer to the file offset - * - * Handle a write to the ALi watchdog. Writing to the file pings - * the watchdog and resets it. Writing the magic 'V' sequence allows - * the next close to turn off the watchdog. - */ - -static ssize_t ali_write(struct file *file, const char __user *data, - size_t len, loff_t *ppos) -{ - /* See if we got the magic character 'V' and reload the timer */ - if (len) { - if (!nowayout) { - size_t i; - - /* note: just in case someone wrote the - magic character five months ago... */ - ali_expect_release = 0; - - /* scan to see whether or not we got - the magic character */ - for (i = 0; i != len; i++) { - char c; - if (get_user(c, data + i)) - return -EFAULT; - if (c == 'V') - ali_expect_release = 42; - } - } - - /* someone wrote to us, we should reload the timer */ - ali_start(); - } - return len; -} - -/* - * ali_ioctl - handle watchdog ioctls - * @file: VFS file pointer - * @cmd: ioctl number - * @arg: arguments to the ioctl - * - * Handle the watchdog ioctls supported by the ALi driver. Really - * we want an extension to enable irq ack monitoring and the like - */ - -static long ali_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - void __user *argp = (void __user *)arg; - int __user *p = argp; - static const struct watchdog_info ident = { - .options = WDIOF_KEEPALIVEPING | - WDIOF_SETTIMEOUT | - WDIOF_MAGICCLOSE, - .firmware_version = 0, - .identity = "ALi M1535 WatchDog Timer", - }; - - switch (cmd) { - case WDIOC_GETSUPPORT: - return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; - - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - return put_user(0, p); - case WDIOC_SETOPTIONS: - { - int new_options, retval = -EINVAL; - - if (get_user(new_options, p)) - return -EFAULT; - if (new_options & WDIOS_DISABLECARD) { - ali_stop(); - retval = 0; - } - if (new_options & WDIOS_ENABLECARD) { - ali_start(); - retval = 0; - } - return retval; - } - case WDIOC_KEEPALIVE: - ali_keepalive(); - return 0; - case WDIOC_SETTIMEOUT: - { - int new_timeout; - if (get_user(new_timeout, p)) - return -EFAULT; - if (ali_settimer(new_timeout)) - return -EINVAL; - ali_keepalive(); - } - /* fall through */ - case WDIOC_GETTIMEOUT: - return put_user(timeout, p); - default: - return -ENOTTY; - } -} - -/* - * ali_open - handle open of ali watchdog - * @inode: inode from VFS - * @file: file from VFS - * - * Open the ALi watchdog device. Ensure only one person opens it - * at a time. Also start the watchdog running. - */ - -static int ali_open(struct inode *inode, struct file *file) -{ - /* /dev/watchdog can only be opened once */ - if (test_and_set_bit(0, &ali_is_open)) - return -EBUSY; - - /* Activate */ - ali_start(); - return nonseekable_open(inode, file); -} - -/* - * ali_release - close an ALi watchdog - * @inode: inode from VFS - * @file: file from VFS - * - * Close the ALi watchdog device. Actual shutdown of the timer - * only occurs if the magic sequence has been set. - */ - -static int ali_release(struct inode *inode, struct file *file) -{ - /* - * Shut off the timer. - */ - if (ali_expect_release == 42) - ali_stop(); - else { - pr_crit("Unexpected close, not stopping watchdog!\n"); - ali_keepalive(); - } - clear_bit(0, &ali_is_open); - ali_expect_release = 0; - return 0; -} - -/* - * ali_notify_sys - System down notifier - * - * Notifier for system down - */ - - -static int ali_notify_sys(struct notifier_block *this, - unsigned long code, void *unused) -{ - if (code == SYS_DOWN || code == SYS_HALT) - ali_stop(); /* Turn the WDT off */ - return NOTIFY_DONE; -} - /* * Data for PCI driver interface * @@ -361,23 +173,17 @@ static int __init ali_find_watchdog(void) * Kernel Interfaces */ -static const struct file_operations ali_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .write = ali_write, - .unlocked_ioctl = ali_ioctl, - .open = ali_open, - .release = ali_release, +static struct watchdog_ops alim1535wdt_ops = { + .owner = THIS_MODULE, + .start = ali_start, + .stop = ali_stop, + .ping = ali_keepalive, + .set_timeout = ali_set_timeout, }; -static struct miscdevice ali_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &ali_fops, -}; - -static struct notifier_block ali_notifier = { - .notifier_call = ali_notify_sys, +static struct watchdog_device alim1535wdt_wdd = { + .ops = &alim1535wdt_ops, + .status = WATCHDOG_NOWAYOUT_INIT_STATUS, }; /* @@ -403,30 +209,25 @@ static int __init watchdog_init(void) timeout); } - /* Calculate the watchdog's timeout */ - ali_settimer(timeout); + watchdog_stop_on_reboot(&alim1535wdt_wdd); + + watchdog_init_timeout(&alim1535wdt_wdd, timeout, NULL); + + watchdog_set_nowayout(&alim1535wdt_wdd, nowayout); - ret = register_reboot_notifier(&ali_notifier); - if (ret != 0) { - pr_err("cannot register reboot notifier (err=%d)\n", ret); - goto out; - } + ret = watchdog_register_device(&alim1535wdt_wdd); - ret = misc_register(&ali_miscdev); if (ret != 0) { - pr_err("cannot register miscdev on minor=%d (err=%d)\n", - WATCHDOG_MINOR, ret); - goto unreg_reboot; + goto reboot_unreg; } - pr_info("initialized. timeout=%d sec (nowayout=%d)\n", - timeout, nowayout); + /* Calculate the watchdog's timeout */ + ali_set_timeout(&alim1535wdt_wdd, timeout); + + return 0; -out: +reboot_unreg: return ret; -unreg_reboot: - unregister_reboot_notifier(&ali_notifier); - goto out; } /* @@ -437,12 +238,8 @@ unreg_reboot: static void __exit watchdog_exit(void) { - /* Stop the timer before we leave */ - ali_stop(); - /* Deregister */ - misc_deregister(&ali_miscdev); - unregister_reboot_notifier(&ali_notifier); + watchdog_unregister_device(&alim1535wdt_wdd); pci_dev_put(ali_pci); } @@ -451,4 +248,4 @@ module_exit(watchdog_exit); MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("ALi M1535 PMU Watchdog Timer driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL");