From: Corey Minyard <minyard@acm.org>
To: linuxppc-dev@ozlabs.org
Subject: MV64x60 watchdog timer driver updates
Date: Thu, 29 Sep 2005 13:32:21 -0500 [thread overview]
Message-ID: <20050929183221.GA17292@i2.minyard.local> (raw)
James looked at an earlier version and said it was ok, and suggested
a few changes. This has been tested against 2.6.14-rc2 on a Katana.
Note that the bus_clk value from the platform information seems to
be in MHZ, but the actual frequency is generally 133,333,333, not
133,000,000. I don't think the inaccuracy matters here, but it seems
a little odd.
-Corey
----
The mv64x60 watchdog timer driver didn't allow dynamically setting
the timeout value. The hardware is settable, and setting the value
is rather important (especially with such a small default). So
this patch adds that function.
It also does the following:
* Modifies the returned timeout to be seconds, not jiffies,
as seconds is the standard.
* Adds a semaphore around the various critical data structures
and access to the device registers. The former operations
could be racy.
* Adds enable and disable operations.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Index: linux-2.6.14-rc2/drivers/char/watchdog/mv64x60_wdt.c
===================================================================
--- linux-2.6.14-rc2.orig/drivers/char/watchdog/mv64x60_wdt.c
+++ linux-2.6.14-rc2/drivers/char/watchdog/mv64x60_wdt.c
@@ -25,12 +25,14 @@
#include <asm/mv64x60.h>
#include <asm/uaccess.h>
#include <asm/io.h>
+#include <asm/semaphore.h>
/* MV64x60 WDC (config) register access definitions */
#define MV64x60_WDC_CTL1_MASK (3 << 24)
#define MV64x60_WDC_CTL1(val) ((val & 3) << 24)
#define MV64x60_WDC_CTL2_MASK (3 << 26)
#define MV64x60_WDC_CTL2(val) ((val & 3) << 26)
+#define MV64x60_WDC_ENABLE (1 << 31)
/* Flags bits */
#define MV64x60_WDOG_FLAG_OPENED 0
@@ -39,44 +41,77 @@
static unsigned long wdt_flags;
static int wdt_status;
static void __iomem *mv64x60_regs;
+static int mv64x60_bus_clk = 133000000;
static int mv64x60_wdt_timeout;
+static u32 mv64x60_wdt_control_val;
+
+static DECLARE_MUTEX(mv64x60_sem);
+
+static u32 mv64x60_wdt_read_reg(void)
+{
+ return readl(mv64x60_regs + MV64x60_WDT_WDC);
+}
static void mv64x60_wdt_reg_write(u32 val)
{
/* Allow write only to CTL1 / CTL2 fields, retaining values in
* other fields.
*/
- u32 data = readl(mv64x60_regs + MV64x60_WDT_WDC);
- data &= ~(MV64x60_WDC_CTL1_MASK | MV64x60_WDC_CTL2_MASK);
- data |= val;
+ u32 data = mv64x60_wdt_control_val | val;
writel(data, mv64x60_regs + MV64x60_WDT_WDC);
}
static void mv64x60_wdt_service(void)
{
/* Write 01 followed by 10 to CTL2 */
+ down(&mv64x60_sem);
mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x01));
mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x02));
+ up(&mv64x60_sem);
+}
+
+static int mv64x60_set_timeout(int timeout)
+{
+ u32 cnt;
+
+ if (timeout > (0xffffffff / mv64x60_bus_clk))
+ return -EINVAL;
+
+ down(&mv64x60_sem);
+ mv64x60_wdt_timeout = timeout;
+
+ /* Put into u32 first so shift will be unsigned. */
+ cnt = timeout * mv64x60_bus_clk;
+ mv64x60_wdt_control_val = cnt >> 8;
+ up(&mv64x60_sem);
+
+ if (test_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags))
+ mv64x60_wdt_service();
+ return 0;
}
static void mv64x60_wdt_handler_disable(void)
{
+ down(&mv64x60_sem);
if (test_and_clear_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) {
/* Write 01 followed by 10 to CTL1 */
mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));
mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));
printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n");
}
+ up(&mv64x60_sem);
}
static void mv64x60_wdt_handler_enable(void)
{
+ down(&mv64x60_sem);
if (!test_and_set_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) {
/* Write 01 followed by 10 to CTL1 */
mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));
mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));
printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n");
}
+ up(&mv64x60_sem);
}
static int mv64x60_wdt_open(struct inode *inode, struct file *file)
@@ -119,6 +154,7 @@ static int mv64x60_wdt_ioctl(struct inod
unsigned int cmd, unsigned long arg)
{
int timeout;
+ int val;
static struct watchdog_info info = {
.options = WDIOF_KEEPALIVEPING,
.firmware_version = 0,
@@ -142,7 +178,14 @@ static int mv64x60_wdt_ioctl(struct inod
return -EOPNOTSUPP;
case WDIOC_SETOPTIONS:
- return -EOPNOTSUPP;
+ if (copy_from_user(&val, (int *) arg, sizeof(int)))
+ return -EFAULT;
+ if (val & WDIOS_DISABLECARD)
+ mv64x60_wdt_handler_disable();
+
+ if (val & WDIOS_ENABLECARD)
+ mv64x60_wdt_handler_enable();
+ return 0;
case WDIOC_KEEPALIVE:
mv64x60_wdt_service();
@@ -150,13 +193,15 @@ static int mv64x60_wdt_ioctl(struct inod
break;
case WDIOC_SETTIMEOUT:
- return -EOPNOTSUPP;
+ if (get_user(timeout, (int *)arg))
+ return -EFAULT;
+ return mv64x60_set_timeout(timeout);
case WDIOC_GETTIMEOUT:
- timeout = mv64x60_wdt_timeout * HZ;
- if (put_user(timeout, (int *)arg))
- return -EFAULT;
- break;
+ timeout = mv64x60_wdt_timeout;
+ if (put_user(timeout, (int *)arg))
+ return -EFAULT;
+ break;
default:
return -ENOIOCTLCMD;
@@ -184,18 +229,25 @@ static int __devinit mv64x60_wdt_probe(s
{
struct platform_device *pd = to_platform_device(dev);
struct mv64x60_wdt_pdata *pdata = pd->dev.platform_data;
- int bus_clk = 133;
+ int timeout = 10;
- mv64x60_wdt_timeout = 10;
if (pdata) {
- mv64x60_wdt_timeout = pdata->timeout;
- bus_clk = pdata->bus_clk;
+ timeout = pdata->timeout;
+ mv64x60_bus_clk = pdata->bus_clk * 1000000;
+ }
+ if (mv64x60_set_timeout(timeout)) {
+ printk("mv64x60_wdt: Default timeout too large, setting to"
+ " maximum value\n");
+ mv64x60_set_timeout(0xffffffff / mv64x60_bus_clk);
}
mv64x60_regs = mv64x60_get_bridge_vbase();
- writel((mv64x60_wdt_timeout * (bus_clk * 1000000)) >> 8,
- mv64x60_regs + MV64x60_WDT_WDC);
+ if (mv64x60_wdt_read_reg() & MV64x60_WDC_ENABLE) {
+ /* Watchdog was already running, disable it */
+ set_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags);
+ mv64x60_wdt_handler_disable();
+ }
return misc_register(&mv64x60_wdt_miscdev);
}
next reply other threads:[~2005-09-29 18:37 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-09-29 18:32 Corey Minyard [this message]
2005-09-29 20:36 ` MV64x60 watchdog timer driver updates Mark A. Greer
2005-09-30 15:10 ` Corey Minyard
2005-09-30 15:18 ` Geert Uytterhoeven
2005-10-03 20:46 ` Mark A. Greer
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=20050929183221.GA17292@i2.minyard.local \
--to=minyard@acm.org \
--cc=linuxppc-dev@ozlabs.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.