Root/target/linux/rdc/patches-2.6.32/110-rdc321x_watchdog_fix.patch

1--- a/drivers/watchdog/rdc321x_wdt.c
2+++ b/drivers/watchdog/rdc321x_wdt.c
3@@ -36,111 +36,99 @@
4 #include <linux/watchdog.h>
5 #include <linux/io.h>
6 #include <linux/uaccess.h>
7+#include <linux/pci.h>
8+#include <linux/delay.h>
9 #include <linux/mfd/rdc321x.h>
10 
11-#define RDC_WDT_MASK 0x80000000 /* Mask */
12+#define RDC321X_WDT_REG 0x00000044
13+
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 */
27 
28-#define RDC_CLS_TMR 0x80003844 /* Clear timer */
29+/* default counter value (2.34 s) */
30+#define RDC_WDT_DFLT_CNT 0x00000040
31 
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)
34 
35 static int ticks = 1000;
36 
37 /* some device data */
38 
39 static struct {
40- struct completion stop;
41- int running;
42     struct timer_list timer;
43- int queue;
44- int default_ticks;
45- unsigned long inuse;
46- spinlock_t lock;
47+ int seconds_left;
48+ int total_seconds;
49+ bool inuse;
50+ bool running;
51+ bool close_expected;
52+
53     struct pci_dev *sb_pdev;
54     int base_reg;
55 } rdc321x_wdt_device;
56 
57-/* generic helper functions */
58+static struct watchdog_info ident = {
59+ .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
60+ .identity = "RDC321x WDT",
61+};
62 
63-static void rdc321x_wdt_trigger(unsigned long unused)
64+
65+/* generic helper functions */
66+static void rdc321x_wdt_timer(unsigned long unused)
67 {
68- unsigned long flags;
69- u32 val;
70+ if (!rdc321x_wdt_device.running) {
71+ pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
72+ rdc321x_wdt_device.base_reg, 0);
73+ return;
74+ }
75 
76- if (rdc321x_wdt_device.running)
77- ticks--;
78+ rdc321x_wdt_device.seconds_left--;
79 
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);
84- val |= RDC_WDT_EN;
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)
89+ return;
90 
91- /* requeue?? */
92- if (rdc321x_wdt_device.queue && ticks)
93- mod_timer(&rdc321x_wdt_device.timer,
94- jiffies + RDC_WDT_INTERVAL);
95- else {
96- /* ticks doesn't matter anyway */
97- complete(&rdc321x_wdt_device.stop);
98- }
99+ pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
100+ rdc321x_wdt_device.base_reg, RDC_WDT_SETUP);
101 
102+ mod_timer(&rdc321x_wdt_device.timer, HZ * 2 + jiffies);
103 }
104 
105 static void rdc321x_wdt_reset(void)
106 {
107- ticks = rdc321x_wdt_device.default_ticks;
108+ rdc321x_wdt_device.seconds_left = rdc321x_wdt_device.total_seconds;
109 }
110 
111 static void rdc321x_wdt_start(void)
112 {
113- unsigned long flags;
114-
115- if (!rdc321x_wdt_device.queue) {
116- rdc321x_wdt_device.queue = 1;
117-
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);
122-
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)
129+ return;
130 
131- mod_timer(&rdc321x_wdt_device.timer,
132- jiffies + RDC_WDT_INTERVAL);
133- }
134+ rdc321x_wdt_device.seconds_left = rdc321x_wdt_device.total_seconds;
135+ rdc321x_wdt_device.running = true;
136+ rdc321x_wdt_timer(0);
137 
138- /* if process dies, counter is not decremented */
139- rdc321x_wdt_device.running++;
140+ return;
141 }
142 
143 static int rdc321x_wdt_stop(void)
144 {
145- if (rdc321x_wdt_device.running)
146- rdc321x_wdt_device.running = 0;
147+ if (WATCHDOG_NOWAYOUT)
148+ return -ENOSYS;
149 
150- ticks = rdc321x_wdt_device.default_ticks;
151+ rdc321x_wdt_device.running = false;
152 
153- return -EIO;
154+ return 0;
155 }
156 
157 /* filesystem operations */
158 static int rdc321x_wdt_open(struct inode *inode, struct file *file)
159 {
160- if (test_and_set_bit(0, &rdc321x_wdt_device.inuse))
161+ if (xchg(&rdc321x_wdt_device.inuse, true))
162         return -EBUSY;
163 
164     return nonseekable_open(inode, file);
165@@ -148,7 +136,16 @@ static int rdc321x_wdt_open(struct inode
166 
167 static int rdc321x_wdt_release(struct inode *inode, struct file *file)
168 {
169- clear_bit(0, &rdc321x_wdt_device.inuse);
170+ int ret;
171+
172+ if (rdc321x_wdt_device.close_expected) {
173+ ret = rdc321x_wdt_stop();
174+ if (ret)
175+ return ret;
176+ }
177+
178+ rdc321x_wdt_device.inuse = false;
179+
180     return 0;
181 }
182 
183@@ -156,30 +153,29 @@ static long rdc321x_wdt_ioctl(struct fil
184                 unsigned long arg)
185 {
186     void __user *argp = (void __user *)arg;
187- u32 value;
188- static struct watchdog_info ident = {
189- .options = WDIOF_CARDRESET,
190- .identity = "RDC321x WDT",
191- };
192- unsigned long flags;
193+ int value;
194 
195     switch (cmd) {
196     case WDIOC_KEEPALIVE:
197         rdc321x_wdt_reset();
198         break;
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)))
206- return -EFAULT;
207- break;
208     case WDIOC_GETSUPPORT:
209         if (copy_to_user(argp, &ident, sizeof(ident)))
210             return -EFAULT;
211         break;
212+ case WDIOC_SETTIMEOUT:
213+ if (copy_from_user(&rdc321x_wdt_device.total_seconds, argp, sizeof(int)))
214+ return -EFAULT;
215+ rdc321x_wdt_device.seconds_left = rdc321x_wdt_device.total_seconds;
216+ break;
217+ case WDIOC_GETTIMEOUT:
218+ if (copy_to_user(argp, &rdc321x_wdt_device.total_seconds, sizeof(int)))
219+ return -EFAULT;
220+ break;
221+ case WDIOC_GETTIMELEFT:
222+ if (copy_to_user(argp, &rdc321x_wdt_device.seconds_left, sizeof(int)))
223+ return -EFAULT;
224+ break;
225     case WDIOC_SETOPTIONS:
226         if (copy_from_user(&value, argp, sizeof(int)))
227             return -EFAULT;
228@@ -194,17 +190,34 @@ static long rdc321x_wdt_ioctl(struct fil
229         }
230         break;
231     default:
232- return -ENOTTY;
233+ return -EINVAL;
234     }
235+
236     return 0;
237 }
238 
239 static ssize_t rdc321x_wdt_write(struct file *file, const char __user *buf,
240                 size_t count, loff_t *ppos)
241 {
242+ size_t i;
243+
244     if (!count)
245         return -EIO;
246 
247+ rdc321x_wdt_device.close_expected = false;
248+
249+ for (i = 0; i != count; i++) {
250+ char c;
251+
252+ if (get_user(c, buf + i))
253+ return -EFAULT;
254+
255+ if (c == 'V') {
256+ rdc321x_wdt_device.close_expected = true;
257+ break;
258+ }
259+ }
260+
261     rdc321x_wdt_reset();
262 
263     return count;
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;
267 
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;
273+
274     err = misc_register(&rdc321x_wdt_misc);
275     if (err < 0) {
276         dev_err(&pdev->dev, "misc_register failed\n");
277         return err;
278     }
279 
280- spin_lock_init(&rdc321x_wdt_device.lock);
281-
282- /* Reset the watchdog */
283- pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
284- rdc321x_wdt_device.base_reg, RDC_WDT_RST);
285-
286- init_completion(&rdc321x_wdt_device.stop);
287- rdc321x_wdt_device.queue = 0;
288-
289- clear_bit(0, &rdc321x_wdt_device.inuse);
290-
291- setup_timer(&rdc321x_wdt_device.timer, rdc321x_wdt_trigger, 0);
292-
293- rdc321x_wdt_device.default_ticks = ticks;
294-
295     dev_info(&pdev->dev, "watchdog init success\n");
296 
297     return 0;
298@@ -274,10 +278,11 @@ static int __devinit rdc321x_wdt_probe(s
299 
300 static int __devexit rdc321x_wdt_remove(struct platform_device *pdev)
301 {
302- if (rdc321x_wdt_device.queue) {
303- rdc321x_wdt_device.queue = 0;
304- wait_for_completion(&rdc321x_wdt_device.stop);
305- }
306+ if (rdc321x_wdt_device.inuse)
307+ rdc321x_wdt_device.inuse = 0;
308+
309+ while (timer_pending(&rdc321x_wdt_device.timer))
310+ msleep(100);
311 
312     misc_deregister(&rdc321x_wdt_misc);
313 
314

Archive Download this file



interactive