1 Index: linux-2.6.30.10/drivers/watchdog/rdc321x_wdt.c
2 ===================================================================
3 --- linux-2.6.30.10.orig/drivers/watchdog/rdc321x_wdt.c 2010-04-28 11:11:44.000000000 +0200
4 +++ linux-2.6.30.10/drivers/watchdog/rdc321x_wdt.c 2010-04-28 11:20:51.000000000 +0200
6 #include <linux/watchdog.h>
8 #include <linux/uaccess.h>
9 +#include <linux/pci.h>
10 +#include <linux/delay.h>
11 #include <linux/mfd/rdc321x.h>
13 -#define RDC_WDT_MASK 0x80000000 /* Mask */
14 +#define RDC321X_WDT_REG 0x00000044
16 #define RDC_WDT_EN 0x00800000 /* Enable bit */
17 -#define RDC_WDT_WTI 0x00200000 /* Generate CPU reset/NMI/WDT on timeout */
18 -#define RDC_WDT_RST 0x00100000 /* Reset bit */
19 -#define RDC_WDT_WIF 0x00040000 /* WDT IRQ Flag */
20 -#define RDC_WDT_IRT 0x00000100 /* IRQ Routing table */
21 -#define RDC_WDT_CNT 0x00000001 /* WDT count */
22 +#define RDC_WDT_WDTIRQ 0x00400000 /* Create WDT IRQ before CPU reset */
23 +#define RDC_WDT_NMIIRQ 0x00200000 /* Create NMI IRQ before CPU reset */
24 +#define RDC_WDT_RST 0x00100000 /* Reset wdt */
25 +#define RDC_WDT_NIF 0x00080000 /* NMI interrupt occured */
26 +#define RDC_WDT_WIF 0x00040000 /* WDT interrupt occured */
27 +#define RDC_WDT_IRT 0x00000700 /* IRQ Routing table */
28 +#define RDC_WDT_CNT 0x0000007F /* WDT count */
30 -#define RDC_CLS_TMR 0x80003844 /* Clear timer */
31 +/* default counter value (2.34 s) */
32 +#define RDC_WDT_DFLT_CNT 0x00000040
34 -#define RDC_WDT_INTERVAL (HZ/10+1)
35 +#define RDC_WDT_SETUP (RDC_WDT_EN | RDC_WDT_NMIIRQ | RDC_WDT_RST | RDC_WDT_DFLT_CNT)
37 static int ticks = 1000;
39 /* some device data */
42 - struct completion stop;
44 struct timer_list timer;
47 - unsigned long inuse;
53 + bool close_expected;
55 struct pci_dev *sb_pdev;
59 -/* generic helper functions */
60 +static struct watchdog_info ident = {
61 + .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
62 + .identity = "RDC321x WDT",
66 -static void rdc321x_wdt_trigger(unsigned long unused)
67 +/* generic helper functions */
68 +static void rdc321x_wdt_timer(unsigned long unused)
70 - unsigned long flags;
72 + if (!rdc321x_wdt_device.running) {
73 + pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
74 + rdc321x_wdt_device.base_reg, 0);
78 - if (rdc321x_wdt_device.running)
80 + rdc321x_wdt_device.seconds_left--;
82 - /* keep watchdog alive */
83 - spin_lock_irqsave(&rdc321x_wdt_device.lock, flags);
84 - pci_read_config_dword(rdc321x_wdt_device.sb_pdev,
85 - rdc321x_wdt_device.base_reg, &val);
87 - pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
88 - rdc321x_wdt_device.base_reg, val);
89 - spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags);
90 + if (rdc321x_wdt_device.seconds_left < 1)
94 - if (rdc321x_wdt_device.queue && ticks)
95 - mod_timer(&rdc321x_wdt_device.timer,
96 - jiffies + RDC_WDT_INTERVAL);
98 - /* ticks doesn't matter anyway */
99 - complete(&rdc321x_wdt_device.stop);
101 + pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
102 + rdc321x_wdt_device.base_reg, RDC_WDT_SETUP);
104 + mod_timer(&rdc321x_wdt_device.timer, HZ * 2 + jiffies);
107 static void rdc321x_wdt_reset(void)
109 - ticks = rdc321x_wdt_device.default_ticks;
110 + rdc321x_wdt_device.seconds_left = rdc321x_wdt_device.total_seconds;
113 static void rdc321x_wdt_start(void)
115 - unsigned long flags;
117 - if (!rdc321x_wdt_device.queue) {
118 - rdc321x_wdt_device.queue = 1;
120 - /* Clear the timer */
121 - spin_lock_irqsave(&rdc321x_wdt_device.lock, flags);
122 - pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
123 - rdc321x_wdt_device.base_reg, RDC_CLS_TMR);
125 - /* Enable watchdog and set the timeout to 81.92 us */
126 - pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
127 - rdc321x_wdt_device.base_reg,
128 - RDC_WDT_EN | RDC_WDT_CNT);
129 - spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags);
130 + if (rdc321x_wdt_device.running)
133 - mod_timer(&rdc321x_wdt_device.timer,
134 - jiffies + RDC_WDT_INTERVAL);
136 + rdc321x_wdt_device.seconds_left = rdc321x_wdt_device.total_seconds;
137 + rdc321x_wdt_device.running = true;
138 + rdc321x_wdt_timer(0);
140 - /* if process dies, counter is not decremented */
141 - rdc321x_wdt_device.running++;
145 static int rdc321x_wdt_stop(void)
147 - if (rdc321x_wdt_device.running)
148 - rdc321x_wdt_device.running = 0;
149 + if (WATCHDOG_NOWAYOUT)
152 - ticks = rdc321x_wdt_device.default_ticks;
153 + rdc321x_wdt_device.running = false;
159 /* filesystem operations */
160 static int rdc321x_wdt_open(struct inode *inode, struct file *file)
162 - if (test_and_set_bit(0, &rdc321x_wdt_device.inuse))
163 + if (xchg(&rdc321x_wdt_device.inuse, true))
166 return nonseekable_open(inode, file);
169 static int rdc321x_wdt_release(struct inode *inode, struct file *file)
171 - clear_bit(0, &rdc321x_wdt_device.inuse);
174 + if (rdc321x_wdt_device.close_expected) {
175 + ret = rdc321x_wdt_stop();
180 + rdc321x_wdt_device.inuse = false;
185 @@ -156,30 +153,29 @@
188 void __user *argp = (void __user *)arg;
190 - static struct watchdog_info ident = {
191 - .options = WDIOF_CARDRESET,
192 - .identity = "RDC321x WDT",
194 - unsigned long flags;
198 case WDIOC_KEEPALIVE:
201 - case WDIOC_GETSTATUS:
202 - /* Read the value from the DATA register */
203 - spin_lock_irqsave(&rdc321x_wdt_device.lock, flags);
204 - pci_read_config_dword(rdc321x_wdt_device.sb_pdev,
205 - rdc321x_wdt_device.base_reg, &value);
206 - spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags);
207 - if (copy_to_user(argp, &value, sizeof(u32)))
210 case WDIOC_GETSUPPORT:
211 if (copy_to_user(argp, &ident, sizeof(ident)))
214 + case WDIOC_SETTIMEOUT:
215 + if (copy_from_user(&rdc321x_wdt_device.total_seconds, argp, sizeof(int)))
217 + rdc321x_wdt_device.seconds_left = rdc321x_wdt_device.total_seconds;
219 + case WDIOC_GETTIMEOUT:
220 + if (copy_to_user(argp, &rdc321x_wdt_device.total_seconds, sizeof(int)))
223 + case WDIOC_GETTIMELEFT:
224 + if (copy_to_user(argp, &rdc321x_wdt_device.seconds_left, sizeof(int)))
227 case WDIOC_SETOPTIONS:
228 if (copy_from_user(&value, argp, sizeof(int)))
230 @@ -194,17 +190,34 @@
241 static ssize_t rdc321x_wdt_write(struct file *file, const char __user *buf,
242 size_t count, loff_t *ppos)
249 + rdc321x_wdt_device.close_expected = false;
251 + for (i = 0; i != count; i++) {
254 + if (get_user(c, buf + i))
258 + rdc321x_wdt_device.close_expected = true;
266 @@ -246,27 +259,18 @@
267 rdc321x_wdt_device.sb_pdev = pdata->sb_pdev;
268 rdc321x_wdt_device.base_reg = r->start;
270 + rdc321x_wdt_device.running = false;
271 + rdc321x_wdt_device.close_expected = false;
272 + rdc321x_wdt_device.inuse = 0;
273 + setup_timer(&rdc321x_wdt_device.timer, rdc321x_wdt_timer, 0);
274 + rdc321x_wdt_device.total_seconds = 100;
276 err = misc_register(&rdc321x_wdt_misc);
278 dev_err(&pdev->dev, "misc_register failed\n");
282 - spin_lock_init(&rdc321x_wdt_device.lock);
284 - /* Reset the watchdog */
285 - pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
286 - rdc321x_wdt_device.base_reg, RDC_WDT_RST);
288 - init_completion(&rdc321x_wdt_device.stop);
289 - rdc321x_wdt_device.queue = 0;
291 - clear_bit(0, &rdc321x_wdt_device.inuse);
293 - setup_timer(&rdc321x_wdt_device.timer, rdc321x_wdt_trigger, 0);
295 - rdc321x_wdt_device.default_ticks = ticks;
297 dev_info(&pdev->dev, "watchdog init success\n");
300 @@ -274,10 +278,11 @@
302 static int rdc321x_wdt_remove(struct platform_device *pdev)
304 - if (rdc321x_wdt_device.queue) {
305 - rdc321x_wdt_device.queue = 0;
306 - wait_for_completion(&rdc321x_wdt_device.stop);
308 + if (rdc321x_wdt_device.inuse)
309 + rdc321x_wdt_device.inuse = 0;
311 + while (timer_pending(&rdc321x_wdt_device.timer))
314 misc_deregister(&rdc321x_wdt_misc);