xref: /linux/drivers/watchdog/alim1535_wdt.c (revision b152ca999c5f11fefdd156a1182e022fa22ebed3)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *	Watchdog for the 7101 PMU version found in the ALi M1535 chipsets
4  */
5 
6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7 
8 #include <linux/module.h>
9 #include <linux/moduleparam.h>
10 #include <linux/types.h>
11 #include <linux/miscdevice.h>
12 #include <linux/watchdog.h>
13 #include <linux/ioport.h>
14 #include <linux/notifier.h>
15 #include <linux/reboot.h>
16 #include <linux/init.h>
17 #include <linux/fs.h>
18 #include <linux/pci.h>
19 #include <linux/uaccess.h>
20 #include <linux/io.h>
21 #include <linux/stringify.h>
22 
23 #define WATCHDOG_NAME "ALi_M1535"
24 #define WATCHDOG_TIMEOUT 60	/* 60 sec default timeout */
25 
26 /* internal variables */
27 static unsigned long ali_is_open;
28 static char ali_expect_release;
29 static struct pci_dev *ali_pci;
30 static u32 ali_timeout_bits;		/* stores the computed timeout */
31 static DEFINE_SPINLOCK(ali_lock);	/* Guards the hardware */
32 
33 /* module parameters */
34 static int timeout = WATCHDOG_TIMEOUT;
35 module_param(timeout, int, 0);
36 MODULE_PARM_DESC(timeout,
37 		"Watchdog timeout in seconds. (0 < timeout < 18000, default="
38 				__stringify(WATCHDOG_TIMEOUT) ")");
39 
40 static bool nowayout = WATCHDOG_NOWAYOUT;
41 module_param(nowayout, bool, 0);
42 MODULE_PARM_DESC(nowayout,
43 		"Watchdog cannot be stopped once started (default="
44 				__stringify(WATCHDOG_NOWAYOUT) ")");
45 
46 /*
47  *	ali_start	-	start watchdog countdown
48  *
49  *	Starts the timer running providing the timer has a counter
50  *	configuration set.
51  */
52 
53 static void ali_start(void)
54 {
55 	u32 val;
56 
57 	spin_lock(&ali_lock);
58 
59 	pci_read_config_dword(ali_pci, 0xCC, &val);
60 	val &= ~0x3F;	/* Mask count */
61 	val |= (1 << 25) | ali_timeout_bits;
62 	pci_write_config_dword(ali_pci, 0xCC, val);
63 
64 	spin_unlock(&ali_lock);
65 }
66 
67 /*
68  *	ali_stop	-	stop the timer countdown
69  *
70  *	Stop the ALi watchdog countdown
71  */
72 
73 static void ali_stop(void)
74 {
75 	u32 val;
76 
77 	spin_lock(&ali_lock);
78 
79 	pci_read_config_dword(ali_pci, 0xCC, &val);
80 	val &= ~0x3F;		/* Mask count to zero (disabled) */
81 	val &= ~(1 << 25);	/* and for safety mask the reset enable */
82 	pci_write_config_dword(ali_pci, 0xCC, val);
83 
84 	spin_unlock(&ali_lock);
85 }
86 
87 /*
88  *	ali_keepalive	-	send a keepalive to the watchdog
89  *
90  *	Send a keepalive to the timer (actually we restart the timer).
91  */
92 
93 static void ali_keepalive(void)
94 {
95 	ali_start();
96 }
97 
98 /*
99  *	ali_settimer	-	compute the timer reload value
100  *	@t: time in seconds
101  *
102  *	Computes the timeout values needed
103  */
104 
105 static int ali_settimer(int t)
106 {
107 	if (t < 0)
108 		return -EINVAL;
109 	else if (t < 60)
110 		ali_timeout_bits = t|(1 << 6);
111 	else if (t < 3600)
112 		ali_timeout_bits = (t / 60)|(1 << 7);
113 	else if (t < 18000)
114 		ali_timeout_bits = (t / 300)|(1 << 6)|(1 << 7);
115 	else
116 		return -EINVAL;
117 
118 	timeout = t;
119 	return 0;
120 }
121 
122 /*
123  *	/dev/watchdog handling
124  */
125 
126 /*
127  *	ali_write	-	writes to ALi watchdog
128  *	@file: file from VFS
129  *	@data: user address of data
130  *	@len: length of data
131  *	@ppos: pointer to the file offset
132  *
133  *	Handle a write to the ALi watchdog. Writing to the file pings
134  *	the watchdog and resets it. Writing the magic 'V' sequence allows
135  *	the next close to turn off the watchdog.
136  */
137 
138 static ssize_t ali_write(struct file *file, const char __user *data,
139 						size_t len, loff_t *ppos)
140 {
141 	/* See if we got the magic character 'V' and reload the timer */
142 	if (len) {
143 		if (!nowayout) {
144 			size_t i;
145 
146 			/* note: just in case someone wrote the
147 			   magic character five months ago... */
148 			ali_expect_release = 0;
149 
150 			/* scan to see whether or not we got
151 			   the magic character */
152 			for (i = 0; i != len; i++) {
153 				char c;
154 				if (get_user(c, data + i))
155 					return -EFAULT;
156 				if (c == 'V')
157 					ali_expect_release = 42;
158 			}
159 		}
160 
161 		/* someone wrote to us, we should reload the timer */
162 		ali_start();
163 	}
164 	return len;
165 }
166 
167 /*
168  *	ali_ioctl	-	handle watchdog ioctls
169  *	@file: VFS file pointer
170  *	@cmd: ioctl number
171  *	@arg: arguments to the ioctl
172  *
173  *	Handle the watchdog ioctls supported by the ALi driver. Really
174  *	we want an extension to enable irq ack monitoring and the like
175  */
176 
177 static long ali_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
178 {
179 	void __user *argp = (void __user *)arg;
180 	int __user *p = argp;
181 	static const struct watchdog_info ident = {
182 		.options =		WDIOF_KEEPALIVEPING |
183 					WDIOF_SETTIMEOUT |
184 					WDIOF_MAGICCLOSE,
185 		.firmware_version =	0,
186 		.identity =		"ALi M1535 WatchDog Timer",
187 	};
188 
189 	switch (cmd) {
190 	case WDIOC_GETSUPPORT:
191 		return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
192 
193 	case WDIOC_GETSTATUS:
194 	case WDIOC_GETBOOTSTATUS:
195 		return put_user(0, p);
196 	case WDIOC_SETOPTIONS:
197 	{
198 		int new_options, retval = -EINVAL;
199 
200 		if (get_user(new_options, p))
201 			return -EFAULT;
202 		if (new_options & WDIOS_DISABLECARD) {
203 			ali_stop();
204 			retval = 0;
205 		}
206 		if (new_options & WDIOS_ENABLECARD) {
207 			ali_start();
208 			retval = 0;
209 		}
210 		return retval;
211 	}
212 	case WDIOC_KEEPALIVE:
213 		ali_keepalive();
214 		return 0;
215 	case WDIOC_SETTIMEOUT:
216 	{
217 		int new_timeout;
218 		if (get_user(new_timeout, p))
219 			return -EFAULT;
220 		if (ali_settimer(new_timeout))
221 			return -EINVAL;
222 		ali_keepalive();
223 	}
224 		fallthrough;
225 	case WDIOC_GETTIMEOUT:
226 		return put_user(timeout, p);
227 	default:
228 		return -ENOTTY;
229 	}
230 }
231 
232 /*
233  *	ali_open	-	handle open of ali watchdog
234  *	@inode: inode from VFS
235  *	@file: file from VFS
236  *
237  *	Open the ALi watchdog device. Ensure only one person opens it
238  *	at a time. Also start the watchdog running.
239  */
240 
241 static int ali_open(struct inode *inode, struct file *file)
242 {
243 	/* /dev/watchdog can only be opened once */
244 	if (test_and_set_bit(0, &ali_is_open))
245 		return -EBUSY;
246 
247 	/* Activate */
248 	ali_start();
249 	return stream_open(inode, file);
250 }
251 
252 /*
253  *	ali_release	-	close an ALi watchdog
254  *	@inode: inode from VFS
255  *	@file: file from VFS
256  *
257  *	Close the ALi watchdog device. Actual shutdown of the timer
258  *	only occurs if the magic sequence has been set.
259  */
260 
261 static int ali_release(struct inode *inode, struct file *file)
262 {
263 	/*
264 	 *      Shut off the timer.
265 	 */
266 	if (ali_expect_release == 42)
267 		ali_stop();
268 	else {
269 		pr_crit("Unexpected close, not stopping watchdog!\n");
270 		ali_keepalive();
271 	}
272 	clear_bit(0, &ali_is_open);
273 	ali_expect_release = 0;
274 	return 0;
275 }
276 
277 /*
278  *	ali_notify_sys	-	System down notifier
279  *
280  *	Notifier for system down
281  */
282 
283 
284 static int ali_notify_sys(struct notifier_block *this,
285 					unsigned long code, void *unused)
286 {
287 	if (code == SYS_DOWN || code == SYS_HALT)
288 		ali_stop();		/* Turn the WDT off */
289 	return NOTIFY_DONE;
290 }
291 
292 /*
293  *	Data for PCI driver interface
294  *
295  *	This data only exists for exporting the supported
296  *	PCI ids via MODULE_DEVICE_TABLE.  We do not actually
297  *	register a pci_driver, because someone else might one day
298  *	want to register another driver on the same PCI id.
299  */
300 
301 static const struct pci_device_id ali_pci_tbl[] __used = {
302 	{ PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,},
303 	{ PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,},
304 	{ 0, },
305 };
306 MODULE_DEVICE_TABLE(pci, ali_pci_tbl);
307 
308 /*
309  *	ali_find_watchdog	-	find a 1535 and 7101
310  *
311  *	Scans the PCI hardware for a 1535 series bridge and matching 7101
312  *	watchdog device. This may be overtight but it is better to be safe
313  */
314 
315 static int __init ali_find_watchdog(void)
316 {
317 	struct pci_dev *pdev;
318 	u32 wdog;
319 
320 	/* Check for a 1533/1535 series bridge */
321 	pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x1535, NULL);
322 	if (pdev == NULL)
323 		pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x1533, NULL);
324 	if (pdev == NULL)
325 		return -ENODEV;
326 	pci_dev_put(pdev);
327 
328 	/* Check for the a 7101 PMU */
329 	pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x7101, NULL);
330 	if (pdev == NULL)
331 		return -ENODEV;
332 
333 	if (pci_enable_device(pdev)) {
334 		pci_dev_put(pdev);
335 		return -EIO;
336 	}
337 
338 	ali_pci = pdev;
339 
340 	/*
341 	 *	Initialize the timer bits
342 	 */
343 	pci_read_config_dword(pdev, 0xCC, &wdog);
344 
345 	/* Timer bits */
346 	wdog &= ~0x3F;
347 	/* Issued events */
348 	wdog &= ~((1 << 27)|(1 << 26)|(1 << 25)|(1 << 24));
349 	/* No monitor bits */
350 	wdog &= ~((1 << 16)|(1 << 13)|(1 << 12)|(1 << 11)|(1 << 10)|(1 << 9));
351 
352 	pci_write_config_dword(pdev, 0xCC, wdog);
353 
354 	return 0;
355 }
356 
357 /*
358  *	Kernel Interfaces
359  */
360 
361 static const struct file_operations ali_fops = {
362 	.owner		=	THIS_MODULE,
363 	.write		=	ali_write,
364 	.unlocked_ioctl =	ali_ioctl,
365 	.compat_ioctl	= 	compat_ptr_ioctl,
366 	.open		=	ali_open,
367 	.release	=	ali_release,
368 };
369 
370 static struct miscdevice ali_miscdev = {
371 	.minor =	WATCHDOG_MINOR,
372 	.name =		"watchdog",
373 	.fops =		&ali_fops,
374 };
375 
376 static struct notifier_block ali_notifier = {
377 	.notifier_call =	ali_notify_sys,
378 };
379 
380 /*
381  *	watchdog_init	-	module initialiser
382  *
383  *	Scan for a suitable watchdog and if so initialize it. Return an error
384  *	if we cannot, the error causes the module to unload
385  */
386 
387 static int __init watchdog_init(void)
388 {
389 	int ret;
390 
391 	/* Check whether or not the hardware watchdog is there */
392 	if (ali_find_watchdog() != 0)
393 		return -ENODEV;
394 
395 	/* Check that the timeout value is within it's range;
396 	   if not reset to the default */
397 	if (timeout < 1 || timeout >= 18000) {
398 		timeout = WATCHDOG_TIMEOUT;
399 		pr_info("timeout value must be 0 < timeout < 18000, using %d\n",
400 			timeout);
401 	}
402 
403 	/* Calculate the watchdog's timeout */
404 	ali_settimer(timeout);
405 
406 	ret = register_reboot_notifier(&ali_notifier);
407 	if (ret != 0) {
408 		pr_err("cannot register reboot notifier (err=%d)\n", ret);
409 		goto out;
410 	}
411 
412 	ret = misc_register(&ali_miscdev);
413 	if (ret != 0) {
414 		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
415 		       WATCHDOG_MINOR, ret);
416 		goto unreg_reboot;
417 	}
418 
419 	pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
420 		timeout, nowayout);
421 
422 out:
423 	return ret;
424 unreg_reboot:
425 	unregister_reboot_notifier(&ali_notifier);
426 	goto out;
427 }
428 
429 /*
430  *	watchdog_exit	-	module de-initialiser
431  *
432  *	Called while unloading a successfully installed watchdog module.
433  */
434 
435 static void __exit watchdog_exit(void)
436 {
437 	/* Stop the timer before we leave */
438 	ali_stop();
439 
440 	/* Deregister */
441 	misc_deregister(&ali_miscdev);
442 	unregister_reboot_notifier(&ali_notifier);
443 	pci_dev_put(ali_pci);
444 }
445 
446 module_init(watchdog_init);
447 module_exit(watchdog_exit);
448 
449 MODULE_AUTHOR("Alan Cox");
450 MODULE_DESCRIPTION("ALi M1535 PMU Watchdog Timer driver");
451 MODULE_LICENSE("GPL");
452