1 --- a/drivers/watchdog/rdc321x_wdt.c
2 +++ b/drivers/watchdog/rdc321x_wdt.c
4 #include <linux/watchdog.h>
6 #include <linux/uaccess.h>
7 +#include <linux/pci.h>
8 +#include <linux/delay.h>
9 #include <linux/mfd/rdc321x.h>
11 -#define RDC_WDT_MASK 0x80000000 /* Mask */
12 +#define RDC321X_WDT_REG 0x00000044
14 #define RDC_WDT_EN 0x00800000 /* Enable bit */
15 -#define RDC_WDT_WTI 0x00200000 /* Generate CPU reset/NMI/WDT on timeout */
16 -#define RDC_WDT_RST 0x00100000 /* Reset bit */
17 -#define RDC_WDT_WIF 0x00040000 /* WDT IRQ Flag */
18 -#define RDC_WDT_IRT 0x00000100 /* IRQ Routing table */
19 -#define RDC_WDT_CNT 0x00000001 /* WDT count */
20 +#define RDC_WDT_WDTIRQ 0x00400000 /* Create WDT IRQ before CPU reset */
21 +#define RDC_WDT_NMIIRQ 0x00200000 /* Create NMI IRQ before CPU reset */
22 +#define RDC_WDT_RST 0x00100000 /* Reset wdt */
23 +#define RDC_WDT_NIF 0x00080000 /* NMI interrupt occured */
24 +#define RDC_WDT_WIF 0x00040000 /* WDT interrupt occured */
25 +#define RDC_WDT_IRT 0x00000700 /* IRQ Routing table */
26 +#define RDC_WDT_CNT 0x0000007F /* WDT count */
28 -#define RDC_CLS_TMR 0x80003844 /* Clear timer */
29 +/* default counter value (2.34 s) */
30 +#define RDC_WDT_DFLT_CNT 0x00000040
32 -#define RDC_WDT_INTERVAL (HZ/10+1)
33 +#define RDC_WDT_SETUP (RDC_WDT_EN | RDC_WDT_NMIIRQ | RDC_WDT_RST | RDC_WDT_DFLT_CNT)
35 static int ticks = 1000;
37 /* some device data */
40 - struct completion stop;
42 struct timer_list timer;
45 - unsigned long inuse;
51 + bool close_expected;
53 struct pci_dev *sb_pdev;
57 -/* generic helper functions */
58 +static struct watchdog_info ident = {
59 + .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
60 + .identity = "RDC321x WDT",
64 -static void rdc321x_wdt_trigger(unsigned long unused)
65 +/* generic helper functions */
66 +static void rdc321x_wdt_timer(unsigned long unused)
68 - unsigned long flags;
70 + if (!rdc321x_wdt_device.running) {
71 + pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
72 + rdc321x_wdt_device.base_reg, 0);
76 - if (rdc321x_wdt_device.running)
78 + rdc321x_wdt_device.seconds_left--;
80 - /* keep watchdog alive */
81 - spin_lock_irqsave(&rdc321x_wdt_device.lock, flags);
82 - pci_read_config_dword(rdc321x_wdt_device.sb_pdev,
83 - rdc321x_wdt_device.base_reg, &val);
85 - pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
86 - rdc321x_wdt_device.base_reg, val);
87 - spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags);
88 + if (rdc321x_wdt_device.seconds_left < 1)
92 - if (rdc321x_wdt_device.queue && ticks)
93 - mod_timer(&rdc321x_wdt_device.timer,
94 - jiffies + RDC_WDT_INTERVAL);
96 - /* ticks doesn't matter anyway */
97 - complete(&rdc321x_wdt_device.stop);
99 + pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
100 + rdc321x_wdt_device.base_reg, RDC_WDT_SETUP);
102 + mod_timer(&rdc321x_wdt_device.timer, HZ * 2 + jiffies);
105 static void rdc321x_wdt_reset(void)
107 - ticks = rdc321x_wdt_device.default_ticks;
108 + rdc321x_wdt_device.seconds_left = rdc321x_wdt_device.total_seconds;
111 static void rdc321x_wdt_start(void)
113 - unsigned long flags;
115 - if (!rdc321x_wdt_device.queue) {
116 - rdc321x_wdt_device.queue = 1;
118 - /* Clear the timer */
119 - spin_lock_irqsave(&rdc321x_wdt_device.lock, flags);
120 - pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
121 - rdc321x_wdt_device.base_reg, RDC_CLS_TMR);
123 - /* Enable watchdog and set the timeout to 81.92 us */
124 - pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
125 - rdc321x_wdt_device.base_reg,
126 - RDC_WDT_EN | RDC_WDT_CNT);
127 - spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags);
128 + if (rdc321x_wdt_device.running)
131 - mod_timer(&rdc321x_wdt_device.timer,
132 - jiffies + RDC_WDT_INTERVAL);
134 + rdc321x_wdt_device.seconds_left = rdc321x_wdt_device.total_seconds;
135 + rdc321x_wdt_device.running = true;
136 + rdc321x_wdt_timer(0);
138 - /* if process dies, counter is not decremented */
139 - rdc321x_wdt_device.running++;
143 static int rdc321x_wdt_stop(void)
145 - if (rdc321x_wdt_device.running)
146 - rdc321x_wdt_device.running = 0;
147 + if (WATCHDOG_NOWAYOUT)
150 - ticks = rdc321x_wdt_device.default_ticks;
151 + rdc321x_wdt_device.running = false;
157 /* filesystem operations */
158 static int rdc321x_wdt_open(struct inode *inode, struct file *file)
160 - if (test_and_set_bit(0, &rdc321x_wdt_device.inuse))
161 + if (xchg(&rdc321x_wdt_device.inuse, true))
164 return nonseekable_open(inode, file);
165 @@ -148,7 +136,16 @@ static int rdc321x_wdt_open(struct inode
167 static int rdc321x_wdt_release(struct inode *inode, struct file *file)
169 - clear_bit(0, &rdc321x_wdt_device.inuse);
172 + if (rdc321x_wdt_device.close_expected) {
173 + ret = rdc321x_wdt_stop();
178 + rdc321x_wdt_device.inuse = false;
183 @@ -156,30 +153,29 @@ static long rdc321x_wdt_ioctl(struct fil
186 void __user *argp = (void __user *)arg;
188 - static struct watchdog_info ident = {
189 - .options = WDIOF_CARDRESET,
190 - .identity = "RDC321x WDT",
192 - unsigned long flags;
196 case WDIOC_KEEPALIVE:
199 - case WDIOC_GETSTATUS:
200 - /* Read the value from the DATA register */
201 - spin_lock_irqsave(&rdc321x_wdt_device.lock, flags);
202 - pci_read_config_dword(rdc321x_wdt_device.sb_pdev,
203 - rdc321x_wdt_device.base_reg, &value);
204 - spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags);
205 - if (copy_to_user(argp, &value, sizeof(u32)))
208 case WDIOC_GETSUPPORT:
209 if (copy_to_user(argp, &ident, sizeof(ident)))
212 + case WDIOC_SETTIMEOUT:
213 + if (copy_from_user(&rdc321x_wdt_device.total_seconds, argp, sizeof(int)))
215 + rdc321x_wdt_device.seconds_left = rdc321x_wdt_device.total_seconds;
217 + case WDIOC_GETTIMEOUT:
218 + if (copy_to_user(argp, &rdc321x_wdt_device.total_seconds, sizeof(int)))
221 + case WDIOC_GETTIMELEFT:
222 + if (copy_to_user(argp, &rdc321x_wdt_device.seconds_left, sizeof(int)))
225 case WDIOC_SETOPTIONS:
226 if (copy_from_user(&value, argp, sizeof(int)))
228 @@ -194,17 +190,34 @@ static long rdc321x_wdt_ioctl(struct fil
239 static ssize_t rdc321x_wdt_write(struct file *file, const char __user *buf,
240 size_t count, loff_t *ppos)
247 + rdc321x_wdt_device.close_expected = false;
249 + for (i = 0; i != count; i++) {
252 + if (get_user(c, buf + i))
256 + rdc321x_wdt_device.close_expected = true;
264 @@ -246,27 +259,18 @@ static int __devinit rdc321x_wdt_probe(s
265 rdc321x_wdt_device.sb_pdev = pdata->sb_pdev;
266 rdc321x_wdt_device.base_reg = r->start;
268 + rdc321x_wdt_device.running = false;
269 + rdc321x_wdt_device.close_expected = false;
270 + rdc321x_wdt_device.inuse = 0;
271 + setup_timer(&rdc321x_wdt_device.timer, rdc321x_wdt_timer, 0);
272 + rdc321x_wdt_device.total_seconds = 100;
274 err = misc_register(&rdc321x_wdt_misc);
276 dev_err(&pdev->dev, "misc_register failed\n");
280 - spin_lock_init(&rdc321x_wdt_device.lock);
282 - /* Reset the watchdog */
283 - pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
284 - rdc321x_wdt_device.base_reg, RDC_WDT_RST);
286 - init_completion(&rdc321x_wdt_device.stop);
287 - rdc321x_wdt_device.queue = 0;
289 - clear_bit(0, &rdc321x_wdt_device.inuse);
291 - setup_timer(&rdc321x_wdt_device.timer, rdc321x_wdt_trigger, 0);
293 - rdc321x_wdt_device.default_ticks = ticks;
295 dev_info(&pdev->dev, "watchdog init success\n");
298 @@ -274,10 +278,11 @@ static int __devinit rdc321x_wdt_probe(s
300 static int __devexit rdc321x_wdt_remove(struct platform_device *pdev)
302 - if (rdc321x_wdt_device.queue) {
303 - rdc321x_wdt_device.queue = 0;
304 - wait_for_completion(&rdc321x_wdt_device.stop);
306 + if (rdc321x_wdt_device.inuse)
307 + rdc321x_wdt_device.inuse = 0;
309 + while (timer_pending(&rdc321x_wdt_device.timer))
312 misc_deregister(&rdc321x_wdt_misc);